shadcn-ui
shadcn/ui — Guia Profissional Completo
shadcn/ui é um conjunto de componentes acessíveis e uma plataforma de distribuição de código. Não é uma biblioteca npm — você copia o código para seu projeto e possui controle total.
Referências Detalhadas
- references/components.md — Catálogo completo de 60+ componentes com código
- references/forms.md — React Hook Form + TanStack Form + Zod
- references/theming.md — CSS Variables, OKLCH, Dark Mode, temas custom
- references/cli-registry.md — CLI 3.0, Registry, MCP Server, Blocks
- references/advanced.md — Data Table, Sidebar, Charts, RTL, Tailwind v4
- references/chart.md — Recharts + ChartConfig detalhado
Quando Usar
- Instalar/configurar shadcn/ui em projeto novo ou existente
- Adicionar componentes individuais (button, dialog, form, table, etc.)
- Construir formulários com validação (React Hook Form ou TanStack Form + Zod)
- Personalizar temas com CSS variables (OKLCH)
- Implementar dark mode
- Configurar Data Tables com TanStack Table
- Montar layouts com Sidebar
- Criar gráficos com Recharts
- Configurar Registry custom ou MCP Server
- Suporte RTL (árabe, hebraico, persa)
Princípios Fundamentais
| Princípio | Descrição |
|---|---|
| Open Code | Código é copiado para seu projeto — você é dono |
| Composição | Interface composable e previsível via data-slot |
| Distribuição | Schema flat-file + CLI para distribuir componentes |
| Beautiful Defaults | Estilos padrão cuidadosamente escolhidos |
| AI-Ready | Código aberto para LLMs lerem e melhorarem |
Quick Start
Novo Projeto (Recomendado)
# Scaffold completo com tema, componentes e presets
npx shadcn@latest create
# OU inicializar em projeto Next.js existente
npx shadcn@latest init
Adicionar Componentes
# Componente individual
npx shadcn@latest add button
# Múltiplos
npx shadcn@latest add button input dialog card select
# Todos
npx shadcn@latest add --all
Uso Básico
import { Button } from "@/components/ui/button"
export default function Page() {
return <Button variant="outline">Click me</Button>
}
Instalação por Framework
| Framework | Comando |
|---|---|
| Next.js | npx shadcn@latest init |
| Vite | npx shadcn@latest init |
| Astro | pnpm dlx shadcn@latest init (requer --template with-tailwindcss --add react) |
| TanStack Start | npx shadcn@latest init |
| React Router | npx shadcn@latest init |
| Laravel | npx shadcn@latest init |
| Manual | Ver docs de instalação manual |
components.json — Configuração do Projeto
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"ui": "@/components/ui",
"utils": "@/lib/utils",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {
"@v0": "https://v0.dev/chat/b/{name}",
"@acme": "https://registry.acme.com/{name}.json"
}
}
Campos importantes:
style:"new-york"(padrão;"default"está deprecado)rsc:trueadiciona"use client"automaticamentetailwind.cssVariables:true= CSS variables (recomendado) /false= utility classestailwind.baseColor:"neutral"|"gray"|"zinc"|"stone"|"slate"registries: Suporta múltiplos registries com autenticação
Sistema de Temas (OKLCH)
CSS Variables Padrão
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
/* ... valores invertidos */
}
Convenção de Nomes
--background→bg-background(fundo do componente)--foreground→text-foreground(texto do componente)--primary/--primary-foreground→ par de cores para elementos primários- Padrão:
bg-{nome}para fundo,text-{nome}-foregroundpara texto
Adicionar Cores Custom
:root {
--warning: oklch(0.84 0.16 84);
--warning-foreground: oklch(0.28 0.07 46);
}
.dark {
--warning: oklch(0.41 0.11 46);
--warning-foreground: oklch(0.99 0.02 95);
}
@theme inline {
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
}
Uso: className="bg-warning text-warning-foreground"
Componentes — Visão Geral
Catálogo Completo (60+ componentes)
Formulários & Input: Button, Button Group, Input, Input Group, Input OTP, Textarea, Checkbox, Radio Group, Select, Native Select, Combobox, Switch, Slider, Calendar, Date Picker, Field, Label, Spinner
Layout & Navegação: Accordion, Breadcrumb, Navigation Menu, Sidebar, Tabs, Separator, Scroll Area, Resizable, Pagination, Kbd
Overlays & Dialogs: Dialog, Alert Dialog, Sheet, Drawer, Popover, Tooltip, Hover Card, Context Menu, Dropdown Menu, Menubar, Command
Feedback & Status: Alert, Sonner (Toast), Progress, Spinner, Skeleton, Badge, Empty
Display & Mídia: Avatar, Card, Table, Data Table, Chart, Carousel, Aspect Ratio, Typography, Item, Toggle, Toggle Group, Collapsible, Direction
Padrão de Uso Universal
// 1. Instalar
// npx shadcn@latest add <componente>
// 2. Importar
import { Component } from "@/components/ui/component"
// 3. Usar
<Component variant="..." size="...">Conteúdo</Component>
Formulários — Padrão Moderno (Field + Controller)
React Hook Form + Zod
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { Controller } from "react-hook-form"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
const schema = z.object({
title: z.string().min(5, "Mínimo 5 caracteres").max(32),
description: z.string().min(20).max(100),
})
export function BugReportForm() {
const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
defaultValues: { title: "", description: "" },
})
return (
<form onSubmit={form.handleSubmit(console.log)} className="space-y-4">
<Controller
name="title"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Título</FieldLabel>
<Input {...field} id={field.name} aria-invalid={fieldState.invalid} />
<FieldDescription>Título conciso do bug.</FieldDescription>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Button type="submit">Enviar</Button>
</form>
)
}
TanStack Form + Zod
"use client"
import { useForm } from "@tanstack/react-form"
import * as z from "zod"
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
const schema = z.object({
title: z.string().min(5).max(32),
})
export function MyForm() {
const form = useForm({
defaultValues: { title: "" },
validators: { onSubmit: schema },
onSubmit: ({ value }) => console.log(value),
})
return (
<form onSubmit={(e) => { e.preventDefault(); form.handleSubmit() }}>
<form.Field
name="title"
children={(field) => {
const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid
return (
<Field data-invalid={isInvalid}>
<FieldLabel htmlFor={field.name}>Título</FieldLabel>
<Input
id={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
aria-invalid={isInvalid}
/>
{isInvalid && <FieldError errors={field.state.meta.errors} />}
</Field>
)
}}
/>
</form>
)
}
CLI 3.0 — Comandos Essenciais
| Comando | Descrição |
|---|---|
npx shadcn@latest init |
Inicializar projeto |
npx shadcn@latest add [comp] |
Adicionar componente(s) |
npx shadcn@latest add --all |
Adicionar todos os componentes |
npx shadcn@latest add @acme/comp |
Instalar de registry custom |
npx shadcn@latest view [item] |
Ver código antes de instalar |
npx shadcn@latest search @registry |
Buscar em registries |
npx shadcn@latest build |
Gerar registry JSON |
npx shadcn@latest migrate rtl [path] |
Migrar para RTL |
npx shadcn@latest migrate radix [path] |
Migrar imports para radix-ui unificado |
npx shadcn@latest create |
Scaffold completo com tema |
Flags importantes do add:
-y— Skip confirmação-o, --overwrite— Sobrescrever arquivos existentes-a, --all— Todos os componentes-p, --path <path>— Caminho customizado
Dark Mode
Next.js (next-themes)
npm install next-themes
// app/providers.tsx
"use client"
import { ThemeProvider } from "next-themes"
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
{children}
</ThemeProvider>
)
}
// app/layout.tsx
import { Providers } from "./providers"
export default function RootLayout({ children }) {
return (
<html lang="pt-BR" suppressHydrationWarning>
<body><Providers>{children}</Providers></body>
</html>
)
}
Toggle de Tema
"use client"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import { MoonIcon, SunIcon } from "lucide-react"
export function ThemeToggle() {
const { setTheme, theme } = useTheme()
return (
<Button variant="ghost" size="icon" onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
<SunIcon className="h-4 w-4 dark:hidden" />
<MoonIcon className="hidden h-4 w-4 dark:block" />
</Button>
)
}
MCP Server — Integração com IA
// .mcp.json (Claude Code)
{
"mcpServers": {
"shadcn": {
"command": "npx",
"args": ["shadcn@latest", "mcp"]
}
}
}
// .cursor/mcp.json (Cursor)
{
"mcpServers": {
"shadcn": {
"command": "npx",
"args": ["shadcn@latest", "mcp"]
}
}
}
Permite buscar, visualizar e instalar componentes via linguagem natural.
Tailwind v4 — Mudanças Críticas
| Antes (v3) | Depois (v4) |
|---|---|
@layer base { :root { --bg: 0 0% 100%; } } |
:root { --bg: oklch(1 0 0); } |
@theme { --color-bg: hsl(var(--bg)); } |
@theme inline { --color-bg: var(--bg); } |
hsl(var(--chart-1)) |
var(--chart-1) |
React.forwardRef<> |
React.ComponentProps<> + data-slot |
w-4 h-4 |
size-4 |
tailwindcss-animate |
tw-animate-css |
| HSL colors | OKLCH colors |
Estilo default |
Estilo new-york (padrão) |
RTL — Suporte Bidirecional
# Migrar componentes existentes
npx shadcn@latest migrate rtl "src/components/ui/**"
- CLI transforma
left-*/right-*→start-*/end-* - Animações:
slide-in-from-right→slide-in-from-end - Adicione
dir="rtl"em portais (Popover, Tooltip, etc.)
Constraints e Avisos
- Não é pacote npm — Componentes copiados ao projeto, você é dono do código
- "use client" obrigatório na maioria dos componentes interativos
- Tailwind CSS é dependência obrigatória
- TypeScript recomendado (suporte JS disponível)
- Path aliases — Configure
@/*no tsconfig.json - Estilo "default" deprecado — Use
"new-york" - Toast deprecado — Use Sonner (
npx shadcn@latest add sonner) - Radix UI ou Base UI — Ambos suportados desde Dez 2025
Best Practices
- Prefira Server Components — Use
"use client"só quando necessário - Composição sobre customização — Use o padrão composable dos componentes
- CSS Variables — Prefira
cssVariables: truepara temas dinâmicos - Acessibilidade — Mantenha
aria-*edata-slotdos componentes - Validação com Zod — Use Standard Schema (Zod v3+) para forms
- Sonner > Toast — Use Sonner para notificações
- data-slot — Cada primitivo tem atributo para estilização targeted
- Field component — Use Field para forms complexos (compatível com todas form libs)