Привет, коллега! Установка shadcn/ui в твой проект на React — это разумное решение и ты попал по адресу. Сегодня я покажу, как за 10–15 минут поднять современную библиотеку компонентов, которая даёт тебе не просто красивые интерфейсы, а полный контроль над кодом. Без магии, без чёрных ящиков — только чистый код, который ты можешь править как угодно.

Почему shadcn/ui? Это не npm-пакет, который ты импортируешь. Это коллекция готовых, доступных компонентов, которые копируются прямо в твой проект. Хочешь изменить стиль кнопки? Правь файл — и всё. Никаких override-стилей, никаких !important.

Почему установка shadcn/ui в React — правильный выбор для современных проектов ?

Прежде чем перейти к коду, давайте честно: зачем вообще заморачиваться с настройкой, если есть Material UI или Ant Design?

Вот три причины, которые убедили меня:

  1. Полный контроль над кодом — компоненты живут в src/components/ui, ты видишь каждую строчку.
  2. Доступность из коробки — ARIA-атрибуты, клавиатурная навигация, фокус-менеджмент уже настроены.
  3. Идеальная интеграция с 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. Ты просто пишешь код — и он работает.

Полезные ссылки

Читайте также