Урок 17. Примеры: установка по шагам

📁 Раздел: shadcn/ui ⏱️ Время изучения: ~50 мин 🎯 Сложность: Средняя

⚡ Кратко

Полный прогон установки с реальным выводом команд, разбор созданных файлов и первая страница на компонентах.

1. Новый проект целиком

npm create vite@latest tailwind-course -- --template react-ts
cd tailwind-course
npm install
npm install tailwindcss @tailwindcss/vite
npm install -D @types/node
📄 src/index.css
@import "tailwindcss";
📄 vite.config.ts
// vite.config.ts
import path from "path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"

export default defineConfig({
  plugins: [react(), tailwindcss()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
})
📄 tsconfig.json
// tsconfig.json — и то же самое в tsconfig.app.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
npx shadcn@latest init
npx shadcn@latest init

✔ Preflight checks.
✔ Verifying framework. Found Vite.
✔ Validating Tailwind CSS. Found v4.
✔ Validating import alias.
✔ Writing components.json.
✔ Checking registry.
✔ Installing dependencies.
✔ Created 2 files:
  - src/components/ui/button.tsx
  - src/lib/utils.ts
✔ Updating src/index.css

Project initialization completed.
You may now add components.

2. Что записал CLI

📄 components.json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "base-nova",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "src/index.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "iconLibrary": "lucide",
  "rtl": false,
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "menuColor": "default",
  "menuAccent": "subtle",
  "registries": {}
}
📄 src/lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

3. Добавляем компоненты

npx shadcn@latest add card input label badge
✔ Checking registry.
✔ Installing dependencies.
✔ Created 4 files:
  - src/components/ui/card.tsx
  - src/components/ui/input.tsx
  - src/components/ui/label.tsx
  - src/components/ui/badge.tsx

4. Первая страница

📄 src/App.tsx
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

export default function App() {
  return (
    <main className="flex min-h-svh items-center justify-center bg-background p-6">
      <Card className="w-full max-w-sm">
        <CardHeader>
          <CardTitle>Вход в систему</CardTitle>
          <CardDescription>Введите почту и пароль</CardDescription>
        </CardHeader>
        <CardContent className="grid gap-3">
          <div className="grid gap-1.5">
            <Label htmlFor="email">Почта</Label>
            <Input id="email" type="email" placeholder="name@example.com" />
          </div>
          <div className="grid gap-1.5">
            <Label htmlFor="password">Пароль</Label>
            <Input id="password" type="password" />
          </div>
        </CardContent>
        <CardFooter className="justify-end gap-2">
          <Button variant="ghost">Отмена</Button>
          <Button>Войти</Button>
        </CardFooter>
      </Card>
    </main>
  )
}

Как это выглядит:

Вход в систему
Введите почту и пароль
<div class="flex justify-center bg-background p-4">
  <div class="w-full 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 gap-1 px-4">
      <div class="text-base leading-snug font-medium">Вход в систему</div>
      <div class="text-sm text-muted-foreground">Введите почту и пароль</div>
    </div>
    <div class="grid gap-3 px-4 pt-3">
      <div class="grid gap-1.5">
        <label class="text-sm leading-none font-medium" for="ex-mail">Почта</label>
        <input id="ex-mail" type="email" placeholder="name@example.com"
               class="h-8 w-full rounded-lg border border-input bg-transparent px-2.5 py-1 text-sm transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50">
      </div>
      <div class="grid gap-1.5">
        <label class="text-sm leading-none font-medium" for="ex-pass">Пароль</label>
        <input id="ex-pass" type="password" value="secret"
               class="h-8 w-full rounded-lg border border-input bg-transparent px-2.5 py-1 text-sm transition-colors outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50">
      </div>
    </div>
    <div class="mt-4 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 hover:bg-primary/80">Войти</button>
    </div>
  </div>
</div>

5. Установка в Next.js

npx create-next-app@latest my-app
cd my-app
npx shadcn@latest init

В Next.js алиас @/ уже настроен шаблоном, а Tailwind подключается через @tailwindcss/postcss. Поле rsc в конфигурации будет true — CLI добавит директиву "use client" в компоненты, которым она нужна.

6. Проверка проекта

npx shadcn@latest info

Команда печатает, что CLI «видит» в вашем проекте: фреймворк, версию Tailwind, путь к CSS, алиасы. Первое, что стоит запустить, если add ведёт себя странно.