Перейти к содержимому

17. shadcn/ui интеграция

Иллюстрация к уроку

shadcn/ui — #1 компонентная библиотека 2024 года. Это НЕ npm-пакет — это коллекция компонентов, которые ты копируешь прямо в свой проект. Полный контроль, нулевая зависимость.

shadcn/ui — набор доступных компонентов на основе:

  • Radix UI — headless компоненты (логика без стилей)
  • Tailwind CSS — стили
  • CVA + tailwind-merge — варианты компонентов

Особенность: ты владеешь кодом. Компоненты живут в components/ui/ твоего проекта.

Окно терминала
# Инициализация shadcn/ui
npx shadcn@latest init
# На вопросы:
# ✔ Which style would you like to use? › Default
# ✔ Which color would you like to use as base color? › Slate
# ✔ Would you like to use CSS variables for colors? › yes

После инициализации появятся:

  • components/ui/ — директория для компонентов
  • lib/utils.ts — функция cn()
  • Обновлённый tailwind.config.ts с CSS-переменными
Окно терминала
# Добавляем нужные компоненты
npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add input
npx shadcn@latest add dialog
npx shadcn@latest add dropdown-menu
npx shadcn@latest add table
npx shadcn@latest add toast
# Или несколько сразу
npx shadcn@latest add button card input dialog

Button:

import { Button } from '@/components/ui/button'
<Button>Кнопка</Button>
<Button variant="outline">Outline</Button>
<Button variant="destructive">Удалить</Button>
<Button variant="ghost" size="sm">Маленький</Button>
<Button disabled>Заблокирован</Button>
<Button size="icon"><PlusIcon /></Button>

Card:

import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from '@/components/ui/card'
<Card>
<CardHeader>
<CardTitle>Заголовок карточки</CardTitle>
<CardDescription>Описание...</CardDescription>
</CardHeader>
<CardContent>
<p>Контент карточки</p>
</CardContent>
<CardFooter>
<Button>Действие</Button>
</CardFooter>
</Card>

Dialog (Modal):

import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
<Dialog>
<DialogTrigger asChild>
<Button>Открыть</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Заголовок модального</DialogTitle>
</DialogHeader>
<p>Контент...</p>
</DialogContent>
</Dialog>

Dropdown Menu:

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Меню</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Профиль</DropdownMenuItem>
<DropdownMenuItem>Настройки</DropdownMenuItem>
<DropdownMenuItem className="text-red-600">Выйти</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

shadcn/ui использует CSS-переменные для цветов, что позволяет легко менять тему:

/* Автоматически добавляется в globals.css */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--border: 214.3 31.8% 91.4%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... */
}
}

Поскольку код в твоём проекте — просто правь его:

// components/ui/button.tsx — найди и измени
const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ...',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
// Добавляем свой вариант:
brand: 'bg-violet-600 text-white hover:bg-violet-700',
},
}
}
)
// Теперь можно использовать:
<Button variant="brand">Брендовая</Button>
КомпонентОписание
ButtonКнопки с вариантами
InputПоле ввода
CardКарточка
DialogМодальное окно
SheetБоковая панель
Dropdown MenuВыпадающее меню
TableТаблица
ToastУведомления
SelectКастомный Select
CalendarКалендарь
CommandCommand palette
DataTableТаблица с TanStack Table