Привет, коллега! Установка shadcn/ui в твой проект на React — это разумное решение и ты попал по адресу. Сегодня я покажу, как за 10–15 минут поднять современную библиотеку компонентов, которая даёт тебе не просто красивые интерфейсы, а полный контроль над кодом. Без магии, без чёрных ящиков — только чистый код, который ты можешь править как угодно.
Почему shadcn/ui? Это не npm-пакет, который ты импортируешь. Это коллекция готовых, доступных компонентов, которые копируются прямо в твой проект. Хочешь изменить стиль кнопки? Правь файл — и всё. Никаких override-стилей, никаких
!important.
Почему установка shadcn/ui в React — правильный выбор для современных проектов ?
Прежде чем перейти к коду, давайте честно: зачем вообще заморачиваться с настройкой, если есть Material UI или Ant Design?
Вот три причины, которые убедили меня:
- Полный контроль над кодом — компоненты живут в
src/components/ui, ты видишь каждую строчку. - Доступность из коробки — ARIA-атрибуты, клавиатурная навигация, фокус-менеджмент уже настроены.
- Идеальная интеграция с Tailwind CSS — стилизуешь через утилитарные классы, как привык.
Совет: Если ты только начинаешь знакомство с shadcn/ui, рекомендую сначала посмотреть официальную документацию, чтобы понять философию проекта.
Шаг 1: Создаём чистый React-проект на Vite
Начнём с нуля. Открываем терминал и пишем:
npm create vite@latest my-shadcn -- --template react
Останавливаем дев-сервер комбинацией Ctrl+C, если он запустился автоматически — нам нужно сначала настроить окружение. После создания проекта переходим в него:
cd my-shadcn
Шаг 2: Подключаем Tailwind CSS v4
Shadcn/ui построен на Tailwind, поэтому без него никуда. Устанавливаем зависимости:
npm install tailwindcss @tailwindcss/vite
Обрати внимание: мы используем @tailwindcss/vite — это официальный плагин для Tailwind CSS v4, который работает напрямую с Vite без PostCSS.
Шаг 3: Настраиваем vite.config.js
Открываем vite.config.js и приводим его к такому виду:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import { dirname, resolve } from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
tailwindcss(),
],
resolve: {
alias: {
"@": resolve(__dirname, "src"),
},
},
server: {
open: true,
host: true,
strictPort: true,
fs: {
strict: false,
},
},
});
Почему это важно:
- Alias
@— shadcn/ui использует его для импортов. Без этой настройки компоненты не найдутся. server.open: true— браузер откроется сам послеnpm run dev. Мелочь, а приятно.
Шаг 4: Добавляем jsconfig.json для алиасов
Чтобы VS Code (и другие редакторы) «понимали» наш алиас @, создаём в корне проекта файл jsconfig.json:
{
"compilerOptions": {
"ignoreDeprecations": "6.0",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
Если ты используешь TypeScript, создай
tsconfig.jsonс аналогичной секциейpaths.
Шаг 5: Подключаем стили Tailwind
Открываем src/index.css и полностью заменяем его содержимое на одну строку:
@import "tailwindcss";
В Tailwind v4 больше не нужны @tailwind base/components/utilities — всё подключается одной директивой. Просто и чисто.
Шаг 6: Правим eslint.config.js
При работе с shadcn/ui может ругаться правило react-refresh/only-export-components. Чтобы не отвлекаться на ложные предупреждения, добавим исключение:
rules: {
'react-refresh/only-export-components': [
'off',
],
},
Итоговый eslint.config.js будет выглядеть примерно так:
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
extends: [
js.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
globals: globals.browser,
parserOptions: { ecmaFeatures: { jsx: true } },
},
rules: {
'react-refresh/only-export-components': [
'off',
],
},
},
])
Шаг 7: Инициализируем shadcn/ui
Всё готово к главному! Запускаем инициализацию:
npx shadcn@latest init
Жми Enter. После успешной инициализации в проекте появятся:
my-shadcn/
├── src/
│ ├── components/
│ │ └── ui/ # здесь будут жить компоненты shadcn
│ ├── lib/
│ │ └── utils.js # вспомогательные утилиты
│ └── index.css # наши стили
└── components.json # конфиг shadcn
Момент истины: если ты видишь папку
src/components/ui— поздравляю, половина пути пройдена!
Шаг 8: Добавляем нужные компоненты
Shadcn/ui работает по принципу «бери только то, что нужно». Добавим набор для демо-дашборда:
npx shadcn@latest add card avatar badge dialog dropdown-menu sonner
После выполнения команды в src/components/ui появятся файлы: button.jsx, card.jsx, avatar.jsx и другие. Каждый из них — это готовый, доступный компонент, который ты можешь править как угодно.
Шаг 9: Пишем демо-приложение в App.jsx
Давай сразу увидим результат! Открываем src/App.jsx и заменяем всё содержимое на этот код:
import { Button } from "./components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./components/ui/card"
import { Avatar, AvatarFallback, AvatarImage } from "./components/ui/avatar"
import { Badge } from "./components/ui/badge"
import { Bell, Heart, Star, User } from "lucide-react"
function App() {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-100 to-gray-200 p-8">
<div className="max-w-6xl mx-auto">
{/* Шапка */}
<div className="flex justify-between items-center mb-8">
<h1 className="text-3xl font-bold text-gray-900">Мой Dashboard</h1>
<div className="flex gap-2">
<Button variant="outline" size="icon">
<Bell className="h-4 w-4" />
</Button>
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</div>
</div>
{/* Сетка карточек */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Всего подписчиков</CardTitle>
<User className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+12,234</div>
<p className="text-xs text-muted-foreground">+20% с прошлого месяца</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Лайки</CardTitle>
<Heart className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+573</div>
<p className="text-xs text-muted-foreground">+201 с прошлой недели</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Рейтинг</CardTitle>
<Star className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">4.8</div>
<p className="text-xs text-muted-foreground">из 5 звезд</p>
</CardContent>
</Card>
</div>
{/* Главная карточка с действиями */}
<Card>
<CardHeader>
<CardTitle>Привет, разработчик! </CardTitle>
<CardDescription>
Вот что можно сделать с shadcn/ui
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex gap-2 flex-wrap">
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
</div>
<div className="flex gap-4">
<Button>Обычная кнопка</Button>
<Button variant="outline">Outline кнопка</Button>
<Button variant="ghost">Ghost кнопка</Button>
<Button variant="destructive">Удалить</Button>
</div>
<div className="flex gap-4">
<Button size="sm">Маленькая</Button>
<Button size="default">Средняя</Button>
<Button size="lg">Большая</Button>
<Button size="icon">
<Star className="h-4 w-4" />
</Button>
</div>
</CardContent>
<CardFooter className="border-t pt-6">
<p className="text-sm text-muted-foreground">
shadcn/ui даёт полный контроль над компонентами — можешь менять всё что хочешь!
</p>
</CardFooter>
</Card>
</div>
</div>
)
}
export default App
Не забудь: файл
src/App.cssможно смело удалить — мы используем только Tailwind-классы.
Шаг 10: Запускаем и наслаждаемся!
Финальный аккорд:
npm run dev
Браузер откроется автоматически, и ты увидишь красивый дашборд с карточками, кнопками, бейджами и аватарами. Всё работает, всё адаптировано, всё доступно.
Чек-лист: всё ли ты сделал правильно?
Пройдись по пунктам, если что-то не заработало:
- В
vite.config.jsдобавлен плагинtailwindcss()и алиас@ - В
jsconfig.jsonпрописаны пути для алиаса - В
src/index.cssтолько@import "tailwindcss"; - В
eslint.config.jsотключено правилоreact-refresh/only-export-components - После
npx shadcn@latest initпоявилась папкаsrc/components/ui - Компоненты добавлены командой
npx shadcn@latest add ...
Не работает? Чаще всего проблема в алиасе
@. Проверь, чтоjsconfig.jsonлежит в корне проекта, а не вsrc/.
Заключения: почему установка shadcn/ui в проект того стоила ?
Когда я впервые попробовал shadcn/ui, меня зацепила одна мысль: «А что, если компоненты — это не чёрный ящик, а просто код, который я могу прочитать и изменить?».
Именно это и даёт shadcn/ui: красивые, доступные интерфейсы без компромиссов. Ты не привязан к версии пакета, не ждёшь фиксов от мейнтейнеров, не борешься со стилями через !important. Ты просто пишешь код — и он работает.
Полезные ссылки
- Официальный сайт shadcn/ui
- Документация по установке
- Коллекция компонентов
- Гайд по кастомизации тем
- Иконки Lucide React (используются в примере)