Урок 16. Примеры: что попадает в проект
⚡ Кратко
Что именно происходит при добавлении компонента и как выглядит результат. Демонстрации ниже воспроизводят внешний вид компонентов реестра на тех же токенах темы.
1. Добавление компонента: вывод команды
npx shadcn@latest add button
✔ Checking registry.
✔ Installing dependencies.
✔ Created 1 file:
- src/components/ui/button.tsx
Обратите внимание: «Created 1 file» — это не установка пакета, а создание файла. Дальше он ваш.
2. Как выглядят варианты Button
<div class="flex flex-wrap items-center gap-3">
<button class="inline-flex h-8 items-center justify-center rounded-lg bg-primary px-2.5 text-sm font-medium text-primary-foreground transition-all hover:bg-primary/80">Default</button>
<button class="inline-flex h-8 items-center justify-center rounded-lg border border-border bg-background px-2.5 text-sm font-medium transition-all hover:bg-muted">Outline</button>
<button class="inline-flex h-8 items-center justify-center rounded-lg bg-secondary px-2.5 text-sm font-medium text-secondary-foreground transition-all">Secondary</button>
<button class="inline-flex h-8 items-center justify-center rounded-lg px-2.5 text-sm font-medium transition-all hover:bg-muted">Ghost</button>
<button class="inline-flex h-8 items-center justify-center rounded-lg bg-destructive/10 px-2.5 text-sm font-medium text-destructive transition-all hover:bg-destructive/20">Destructive</button>
<button class="inline-flex h-8 items-center justify-center rounded-lg px-2.5 text-sm font-medium text-primary underline-offset-4 hover:underline">Link</button>
</div>
Все шесть вариантов описаны в одном файле таблицей cva —
ровно так, как мы делали в уроке 15, только с семантическими токенами
вместо конкретных цветов.
3. Карточка из подкомпонентов
Карточка собирается из Card, CardHeader, CardTitle, CardDescription, CardContent и CardFooter.
<div class="max-w-sm overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10">
<div class="grid auto-rows-min items-start gap-1 px-4">
<div class="text-base leading-snug font-medium">Ежемесячный отчёт</div>
<div class="text-sm text-muted-foreground">Данные за июль 2026</div>
</div>
<div class="px-4">
<p class="text-muted-foreground">Карточка собирается из Card, CardHeader, CardTitle, CardDescription, CardContent и CardFooter.</p>
</div>
<div class="flex items-center justify-end gap-2 rounded-b-xl border-t bg-muted/50 p-4">
<button class="inline-flex h-8 items-center justify-center rounded-lg px-2.5 text-sm font-medium hover:bg-muted">Отмена</button>
<button class="inline-flex h-8 items-center justify-center rounded-lg bg-primary px-2.5 text-sm font-medium text-primary-foreground">Открыть</button>
</div>
</div>
<Card>
<CardHeader>
<CardTitle>Ежемесячный отчёт</CardTitle>
<CardDescription>Данные за июль 2026</CardDescription>
</CardHeader>
<CardContent>…</CardContent>
<CardFooter>
<Button variant="ghost">Отмена</Button>
<Button>Открыть</Button>
</CardFooter>
</Card>
4. Правка компонента — обычное редактирование файла
// src/components/ui/button.tsx — добавляем свой вариант
const buttonVariants = cva("…", {
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/80",
outline: "border-border bg-background hover:bg-muted",
// ← ваш вариант: столько же прав, сколько у встроенных
brand: "bg-brand text-brand-foreground hover:opacity-90",
},
},
})
<button class="inline-flex h-8 items-center justify-center rounded-lg bg-brand px-3 text-sm font-medium text-brand-foreground transition-all hover:opacity-90">
variant="brand"
</button>
С обычной библиотекой такой вариант пришлось бы «доклеивать» снаружи
через sx, styled() или переопределение темы.
5. Атрибуты-слоты
<div data-slot="card">
<div data-slot="card-header">
<div data-slot="card-title">Заголовок</div>
</div>
</div>
Каждая часть компонента помечена data-slot. Это удобно
и для стилизации (has-data-[slot=card-footer]:pb-0),
и для тестов: селектор по слоту устойчивее, чем по классам.
6. Доступность, которую вы получаете бесплатно
<Dialog>
<DialogTrigger render={<Button>Открыть</Button>} />
<DialogContent>
<DialogTitle>Подтвердите действие</DialogTitle>
</DialogContent>
</Dialog>
За четырьмя строками — фокус-ловушка, возврат фокуса на кнопку после
закрытия, закрытие по Esc, блокировка прокрутки, портал в конец
документа, связка aria-labelledby с заголовком. Написать это
вручную — несколько дней работы и десятки краевых случаев.