What You’ll Learn in This Tutorial
✓ shadcn/ui setup
✓ Adding components
✓ Theme customization
✓ Form building
✓ Dark mode
Step 1: Setup
npx create-next-app@latest my-app --typescript --tailwind
cd my-app
npx shadcn-ui@latest init
Select the following in initial setup:
- TypeScript: yes
- Style: Default
- Base color: Slate
- CSS variables: yes
Step 2: Adding Components
# Add individually
npx shadcn-ui@latest add button
npx shadcn-ui@latest add card
npx shadcn-ui@latest add input
npx shadcn-ui@latest add form
# Add multiple
npx shadcn-ui@latest add button card input dialog
Step 3: Basic Usage
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
export default function HomePage() {
return (
<div className="p-8">
<Card className="max-w-md">
<CardHeader>
<CardTitle>Login</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<Input placeholder="Email" />
<Input type="password" placeholder="Password" />
<Button className="w-full">Login</Button>
</CardContent>
</Card>
</div>
);
}
Step 4: Variants
<Button variant="default">Default</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
Step 5: Form Building
npx shadcn-ui@latest add form
npm install zod react-hook-form @hookform/resolvers
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
const schema = z.object({
email: z.string().email('Enter a valid email'),
password: z.string().min(8, '8 characters minimum'),
});
export function LoginForm() {
const form = useForm({
resolver: zodResolver(schema),
defaultValues: { email: '', password: '' },
});
const onSubmit = (data: z.infer<typeof schema>) => {
console.log(data);
};
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 {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full">Login</Button>
</form>
</Form>
);
}
Step 6: Dialog
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
export function ConfirmDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="destructive">Delete</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
This action cannot be undone.
</DialogDescription>
</DialogHeader>
<div className="flex justify-end gap-2">
<Button variant="outline">Cancel</Button>
<Button variant="destructive">Delete</Button>
</div>
</DialogContent>
</Dialog>
);
}
Step 7: Theme Customization
/* globals.css */
@layer base {
:root {
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
/* Custom colors */
}
.dark {
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
}
}
Summary
shadcn/ui is a copy-paste UI library with full customization capability. It’s based on Radix UI and Tailwind CSS.
← Back to list