What is shadcn/ui? Complete Tutorial (2026)
Build beautiful UIs with copy-paste components you actually own
Start Building with Hypereal
Access Kling, Flux, Sora, Veo & more through a single API. Free credits to start, scale to millions.
No credit card required • 100k+ developers • Enterprise ready
What is shadcn/ui? Complete Tutorial for 2026
shadcn/ui is not a traditional component library -- it is a collection of reusable, beautifully designed components that you copy directly into your project. Instead of installing an npm package and importing opaque components, you get the actual source code in your codebase, giving you full control over styling, behavior, and accessibility.
Built on top of Radix UI primitives and styled with Tailwind CSS, shadcn/ui has become one of the most popular frontend tools in the React ecosystem. This tutorial covers everything from initial setup to advanced customization.
Why shadcn/ui?
Here is how shadcn/ui compares to traditional component libraries:
| Feature | shadcn/ui | Material UI | Chakra UI | Ant Design |
|---|---|---|---|---|
| Installation | Copy to your project | npm package | npm package | npm package |
| Own the code | Yes | No | No | No |
| Styling | Tailwind CSS | Emotion/styled | Emotion | Less/CSS-in-JS |
| Bundle size | Only what you use | Large | Medium | Large |
| Customization | Full (edit source) | Theme overrides | Theme overrides | Theme overrides |
| Accessibility | Radix UI (excellent) | Good | Good | Good |
| TypeScript | Full support | Full support | Full support | Full support |
| Framework | React / Next.js | React | React | React |
The key advantage: when you need to customize a component's behavior or styling beyond what theme overrides allow, you edit the actual component code rather than fighting against library abstractions.
Step 1: Set Up a New Project
shadcn/ui works best with Next.js, but also supports Vite, Remix, Astro, and other React frameworks.
With Next.js (Recommended)
npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir
cd my-app
With Vite
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm install -D tailwindcss @tailwindcss/vite
Step 2: Initialize shadcn/ui
Run the CLI to set up shadcn/ui in your project:
npx shadcn@latest init
The CLI will ask you a few questions:
Which style would you like to use? > New York
Which color would you like to use as base color? > Zinc
Do you want to use CSS variables for colors? > Yes
This creates:
- A
components.jsonconfiguration file - A
lib/utils.tsfile with thecn()utility function - Updated Tailwind and global CSS configuration
Here is what the generated components.json looks like:
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css",
"baseColor": "zinc",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}
Step 3: Add Components
Add components individually as you need them:
# Add a button component
npx shadcn@latest add button
# Add multiple components at once
npx shadcn@latest add card dialog dropdown-menu input label
# Add all components (not recommended -- add what you need)
npx shadcn@latest add --all
Each command copies the component source code into your src/components/ui/ directory. For example, adding the button creates:
// src/components/ui/button.tsx
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
// ... rest of component
Step 4: Use Components in Your App
Import and use components like any other React component:
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
export default function LoginPage() {
return (
<div className="flex min-h-screen items-center justify-center">
<Card className="w-[400px]">
<CardHeader>
<CardTitle>Sign In</CardTitle>
<CardDescription>Enter your credentials to access your account.</CardDescription>
</CardHeader>
<CardContent>
<form className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="you@example.com" />
</div>
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
<Input id="password" type="password" />
</div>
<Button type="submit" className="w-full">
Sign In
</Button>
</form>
</CardContent>
</Card>
</div>
)
}
Step 5: Customize the Theme
shadcn/ui uses CSS variables for theming. Edit your globals.css to change colors:
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--border: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--radius: 0.5rem;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
/* ... dark mode values */
}
}
The shadcn/ui website has a theme generator where you can visually pick colors and copy the CSS variables.
Step 6: Build a Complex Component
Since you own the code, you can extend components freely. Here is an example of building a data table with sorting, filtering, and pagination using shadcn/ui:
# Add required components
npx shadcn@latest add table badge select
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { useState } from "react"
interface User {
id: number
name: string
email: string
role: "admin" | "user" | "moderator"
status: "active" | "inactive"
}
const users: User[] = [
{ id: 1, name: "Alice Johnson", email: "alice@example.com", role: "admin", status: "active" },
{ id: 2, name: "Bob Smith", email: "bob@example.com", role: "user", status: "active" },
{ id: 3, name: "Carol Davis", email: "carol@example.com", role: "moderator", status: "inactive" },
]
export function UserTable() {
const [search, setSearch] = useState("")
const filtered = users.filter(
(user) =>
user.name.toLowerCase().includes(search.toLowerCase()) ||
user.email.toLowerCase().includes(search.toLowerCase())
)
return (
<div className="space-y-4">
<Input
placeholder="Search users..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="max-w-sm"
/>
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filtered.map((user) => (
<TableRow key={user.id}>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>
<Badge variant="outline">{user.role}</Badge>
</TableCell>
<TableCell>
<Badge variant={user.status === "active" ? "default" : "secondary"}>
{user.status}
</Badge>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)
}
Essential Components to Start With
Here are the most commonly used shadcn/ui components:
| Component | Use Case | Dependencies |
|---|---|---|
| Button | Actions and CTAs | None |
| Input | Text inputs | None |
| Card | Content containers | None |
| Dialog | Modals and popups | Radix Dialog |
| Dropdown Menu | Context menus | Radix Dropdown |
| Table | Data display | None |
| Form | Form handling | React Hook Form + Zod |
| Toast | Notifications | Sonner |
| Sheet | Side panels | Radix Dialog |
| Tabs | Tabbed interfaces | Radix Tabs |
| Command | Search / command palette | cmdk |
Frequently Asked Questions
Is shadcn/ui free? Yes, completely free and open source under the MIT license.
Does shadcn/ui increase my bundle size? No. Since you only add the components you use, and they are part of your source code, tree-shaking works perfectly. Your bundle only includes what you import.
Can I use shadcn/ui with plain React (no Next.js)? Yes. shadcn/ui supports Vite, Remix, Astro, and other React frameworks. The CLI handles the setup for each.
How do I update components?
Run npx shadcn@latest diff to see changes between your local components and the latest versions. Then selectively apply updates.
Can I use shadcn/ui with other CSS frameworks? shadcn/ui is designed for Tailwind CSS. Using it with other CSS frameworks would require significant modifications.
Is shadcn/ui accessible? Yes. Most interactive components are built on Radix UI primitives, which provide excellent keyboard navigation, screen reader support, and WAI-ARIA compliance.
Wrapping Up
shadcn/ui represents a shift in how we think about component libraries. Instead of depending on an external package that controls your UI, you get beautifully designed, accessible components that live in your codebase. This approach gives you complete control over customization while still benefiting from well-tested patterns.
If you are building a frontend that connects to AI services for media generation, try Hypereal AI free -- 35 credits, no credit card required. The API works with any React frontend, and shadcn/ui components make it easy to build polished UIs around AI-generated content.
Related Articles
Start Building Today
Get 35 free credits on signup. No credit card required. Generate your first image in under 5 minutes.
