shadcn-ui
Shadcn UI for Next.js
Overview
Shadcn UI is a collection of re-usable components built on Radix UI and Tailwind CSS. It is not an npm package — instead, a CLI copies component source code directly into the project at components/ui/. This gives full ownership and control over every component. All components are accessible by default (via Radix), styled with Tailwind CSS, and composable.
Official docs: https://ui.shadcn.com
Quick Start
Initialize Shadcn UI in an existing Next.js project:
npx shadcn@latest init
Add components as needed:
npx shadcn@latest add button card dialog
Import and use:
import { Button } from "@/components/ui/button"
export default function Page() {
return <Button variant="outline">Click me</Button>
}
For the full CLI reference (all commands, flags,
components.jsonschema), seereferences/cli-and-configuration.md.
Core Workflow
Follow this standard process when building with Shadcn UI:
- Initialize — Run
npx shadcn@latest initto generatecomponents.jsonand set up paths - Add components — Run
npx shadcn@latest add [name]for each component needed - Compose UI — Combine components in pages and layouts, wrap interactive ones with
"use client" - Theme — Configure CSS variables in
globals.cssfor light/dark mode - Customize — Edit component source directly in
components/ui/when needed
Component Import Convention
All Shadcn components install to components/ui/ and use the @/ path alias:
import { Button } from "@/components/ui/button"
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
import { Dialog, DialogTrigger, DialogContent } from "@/components/ui/dialog"
Every Shadcn component is a Client Component internally (uses Radix UI hooks). When using them in Next.js App Router:
- Import them in files that have
"use client"at the top, OR - Import them inside a Client Component wrapper
For the full component catalog (categorized, with install commands, imports, and variants), see
references/components.md.
Next.js App Router Integration
Server vs Client Components
Shadcn components use Radix UI primitives (hooks, refs, event handlers), so they require the client runtime. Apply these rules:
| Scenario | Approach |
|---|---|
| Page with only Shadcn components | Add "use client" to the page file |
| Page mixing data fetching + UI | Keep page as Server Component; extract interactive parts into a Client Component |
| Layout with providers | Add providers in a "use client" wrapper component |
Provider Setup in layout.tsx
Place global providers in a dedicated Client Component:
// app/providers.tsx
"use client"
import { ThemeProvider } from "next-themes"
import { TooltipProvider } from "@/components/ui/tooltip"
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<TooltipProvider>
{children}
</TooltipProvider>
</ThemeProvider>
)
}
// app/layout.tsx (Server Component)
import { Providers } from "./providers"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
For layout patterns, responsive design, and component composition, see
references/composition-patterns.md.
Form Building
Shadcn forms use React Hook Form + Zod for validation + Shadcn Form components for UI:
npx shadcn@latest add form input label
npm install zod
Core pattern:
"use client"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
const schema = z.object({
email: z.string().email(),
name: z.string().min(2),
})
export function MyForm() {
const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
defaultValues: { email: "", name: "" },
})
function onSubmit(values: z.infer<typeof schema>) {
// handle submission
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField control={form.control} name="email" render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl><Input placeholder="email@example.com" {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<Button type="submit">Submit</Button>
</form>
</Form>
)
}
For advanced form patterns (select, checkbox, date picker, dynamic arrays, Server Actions), see
references/forms.mdandexamples/form-with-validation.tsx.
Data Tables
Shadcn data tables use TanStack Table with a 3-file architecture:
npx shadcn@latest add table
npm install @tanstack/react-table
| File | Purpose |
|---|---|
columns.tsx |
Define ColumnDef[] with accessors, headers, cell renderers |
data-table.tsx |
Reusable <DataTable> component with useReactTable |
page.tsx |
Fetch data (Server Component) and pass to <DataTable> |
For column definitions, sorting, filtering, pagination, and row selection patterns, see
references/data-tables.mdandexamples/data-table-example.tsx.
Theming
Shadcn UI uses CSS variables in globals.css for all color tokens. Modern Shadcn uses the oklch color format:
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
/* ... */
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
/* ... */
}
Enable dark mode with next-themes:
npm install next-themes
For the complete variable list, dark mode toggle component, TweakCN editor workflow, sidebar tokens, and custom colors, see
references/theming-and-dark-mode.md.
Charts
Shadcn Charts wrap Recharts with themed components:
npx shadcn@latest add chart
npm install recharts
Core pattern: define a ChartConfig object mapping data keys to labels and colors, wrap Recharts components in <ChartContainer>:
const chartConfig = {
desktop: { label: "Desktop", color: "var(--chart-1)" },
mobile: { label: "Mobile", color: "var(--chart-2)" },
} satisfies ChartConfig
For all chart types, tooltip/legend configuration, and responsive patterns, see
references/charts.mdandexamples/chart-config-example.tsx.
Blocks
Blocks are pre-built, full-page or section-level compositions (dashboards, login pages, sidebars). Copy the block source into the project and install required components.
For the block catalog, file structures, dependencies, and the sidebar system, see
references/blocks.mdandexamples/dashboard-layout.tsx.
Key Rules
| Do | Don't |
|---|---|
Use npx shadcn@latest add to install components |
Install components via npm |
Import from @/components/ui/... |
Import from shadcn or @shadcn/ui |
Use CSS variables for theming (oklch) |
Hardcode color values in components |
Add "use client" when using interactive components |
Use Shadcn components in Server Components without a client wrapper |
Edit component source in components/ui/ to customize |
Create wrapper components for simple style changes |
| Install all dependencies for blocks | Copy block code without its required components |
Reference Files
Detailed Guides
references/cli-and-configuration.md— CLI commands,components.jsonschema, aliases, package managersreferences/components.md— Full component catalog categorized by type with variants and importsreferences/composition-patterns.md— Layout patterns, Server/Client components, providers, responsive designreferences/forms.md— React Hook Form + Zod + Shadcn Form component patternsreferences/data-tables.md— TanStack Table integration, columns, sorting, filtering, paginationreferences/charts.md— Recharts integration, ChartConfig, all chart types, tooltipsreferences/blocks.md— Block catalog, sidebar system, dashboard patterns, dependenciesreferences/theming-and-dark-mode.md— CSS variables, oklch, next-themes, TweakCN, custom colorsreferences/accessibility.md— Built-in Radix a11y, developer responsibilities, ARIA patterns
Code Examples
examples/form-with-validation.tsx— Complete form with Zod schema, multiple field types, submit handlerexamples/data-table-example.tsx— Data table with columns, sorting, and paginationexamples/dashboard-layout.tsx— Dashboard layout with sidebar, header, and content areaexamples/chart-config-example.tsx— Bar chart with full ChartConfig, tooltip, and legend