| name | shadcn-ui-expert |
| description | Develop high-quality, accessible React components using shadcn-ui, Tailwind CSS, and Radix UI. Use when building forms, layouts, dialogs, tables, or any UI components. Supports Next.js, Vite, Remix, Astro, and more. Integrates with shadcn MCP server for component discovery and installation. |
| allowed-tools | Read, Grep, Glob, Write, Shell |
shadcn-ui Expert
shadcn-ui is a collection of beautifully-designed, accessible React components built with TypeScript, Tailwind CSS, and Radix UI primitives. This skill guides you through component selection, implementation, customization, and best practices.
Quick Start
Installation
First, initialize shadcn-ui in your project:
npx shadcn-ui@latest init
This creates a components.json file for configuration. Choose your framework:
- Next.js (App Router recommended)
- Vite
- Remix
- Astro
- Laravel
- Gatsby
- React Router
- TanStack Router/Start
Installing Components
Use the CLI to install individual components:
# Install a button component
npx shadcn-ui@latest add button
# Install form components
npx shadcn-ui@latest add form input select checkbox
# Install a data table
npx shadcn-ui@latest add data-table
Or ask me directly to "add a login form" - I can use the MCP server to handle installation with natural language.
Component Categories
Form & Input Components
Use for: Data collection, user input, validation
form- Complex forms with React Hook Forminput- Text fieldstextarea- Multi-line textselect- Dropdown selectionscheckbox- Boolean inputsradio-group- Single selection from optionsswitch- Toggle boolean statesdate-picker- Date selectioncombobox- Searchable select with autocomplete
Layout & Navigation
Use for: App structure, navigation flows, content organization
sidebar- Collapsible side navigationtabs- Tabbed contentaccordion- Collapsible sectionsbreadcrumb- Navigation pathnavigation-menu- Dropdown menusscroll-area- Custom scrollable regions
Overlays & Dialogs
Use for: Modals, confirmations, floating content
dialog- Modal dialogsalert-dialog- Confirmation promptsdrawer- Mobile-friendly side panelspopover- Floating popoverstooltip- Hover informationdropdown-menu- Menu dropdownscontext-menu- Right-click menus
Data Display
Use for: Showing structured data
table- Basic HTML tablesdata-table- Advanced tables with sorting/filtering/paginationavatar- User profile imagesbadge- Status labelscard- Content containers
Feedback & Status
Use for: User feedback, loading states, alerts
alert- Alert messagestoast- Notificationsprogress- Progress barsskeleton- Loading placeholdersspinner- Loading indicators
Component Selection Guide
Ask yourself these questions to choose the right component:
What is the user interacting with?
- Text input → use
input - Choosing from options → use
selectorcombobox - Yes/no decision → use
checkboxorswitch - Multiple fields → use
form
- Text input → use
How should it be displayed?
- Inline with other content →
input,select - Centered on screen →
dialog - Slide from side →
drawer - Information tooltip →
tooltip
- Inline with other content →
What's the context?
- Inside a form → use
fieldcomponent withform - Standalone button → use
button - Inside a table → use table row cell or
data-table
- Inside a form → use
Does it need validation?
- Yes → combine
form+field+ React Hook Form - No → use simple components (
input,select)
- Yes → combine
Common Implementation Patterns
Basic Form with Validation
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import { Form, FormField, FormItem, FormLabel, FormControl } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
const formSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
})
export function LoginForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
})
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="you@example.com" {...field} />
</FormControl>
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
)
}
Dialog Pattern
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
export function DeleteDialog() {
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 gap-3 justify-end">
<Button variant="outline">Cancel</Button>
<Button variant="destructive">Delete</Button>
</div>
</DialogContent>
</Dialog>
)
}
Styling & Customization
All components use Tailwind CSS for styling. Customize appearance through:
1. Tailwind Classes
Add classes directly to components:
<Button className="w-full text-lg">Full Width</Button>
<Input className="rounded-lg border-2" />
2. CSS Variables (Theme Colors)
shadcn/ui uses CSS variables for theming. Edit app/globals.css:
@layer base {
:root {
--primary: 222.2 47.4% 11.2%;
--secondary: 210 40% 96%;
}
}
3. Dark Mode
Enable dark mode in your framework:
- Next.js: Configure in
next.config.js - Vite: Add dark class detection in
tailwind.config.js - Components automatically respond to
darkclass
4. Component Variants
Many components have built-in variants:
<Button variant="outline" />
<Button variant="ghost" />
<Button variant="destructive" />
<Badge variant="secondary" />
Composition & Best Practices
1. Composition Over Customization
Combine small components rather than modifying large ones:
// ✅ Good: Compose components
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
</CardHeader>
<CardContent>
<Form>...</Form>
</CardContent>
</Card>
// ❌ Avoid: Over-modifying single component
<CustomDialog withHeader={true} withForm={true} />
2. Use Type Safety
Leverage TypeScript for prop safety:
import { Button } from "@/components/ui/button"
import type { ButtonProps } from "@/components/ui/button"
type CustomButtonProps = ButtonProps & {
label: string
}
3. Accessibility Built-in
shadcn/ui uses Radix UI primitives with accessibility built-in:
- Keyboard navigation
- ARIA attributes
- Screen reader support
- Focus management
Just use components correctly; accessibility comes free.
4. Performance
- Components are small and modular
- Tree-shakeable
- No runtime overhead beyond Radix UI
- Use
React.memofor frequently-rerendered components if needed
Framework-Specific Notes
Next.js
- Use
shadcn-ui@latest add formfor React Hook Form integration - Combine with Server Actions for form submissions
- Dark mode works via
next-themes
Vite
- Ensure
tailwind.config.jsincludes component paths - Use Vite's HMR for fast development
Remix
- Forms work with
remixform actions - Use route transitions for optimistic updates
Common Customization Tasks
Changing Primary Color
Edit components.json during init or manually update CSS variables in globals.css.
Adding Custom Components
Create your own components in components/ui/ following shadcn/ui patterns:
// components/ui/my-component.tsx
import * as React from "react"
export interface MyComponentProps
extends React.HTMLAttributes<HTMLDivElement> {}
const MyComponent = React.forwardRef<HTMLDivElement, MyComponentProps>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={className}
{...props}
/>
)
)
MyComponent.displayName = "MyComponent"
export { MyComponent }
Theming for Multiple Brands
Use CSS variable layers:
.brand-a {
--primary: 220 90% 56%;
--secondary: 0 0% 100%;
}
.brand-b {
--primary: 0 100% 50%;
--secondary: 200 100% 50%;
}
Validation & Forms
With React Hook Form + Zod
Best practice for complex forms with client-side validation:
npm install react-hook-form zod @hookform/resolvers
With TanStack Form
Alternative for advanced form requirements:
npm install @tanstack/react-form
Ask me for specific form patterns (login, signup, multi-step, etc.)
Troubleshooting
Components Not Styling Correctly
- ✅ Verify Tailwind is configured in
tailwind.config.js - ✅ Check
components.jsonhas correctpathsetting - ✅ Run
npm installafter adding components
TypeScript Errors
- ✅ Ensure components are imported from
/components/ui/name - ✅ Components have proper TypeScript support built-in
Form Validation Not Working
- ✅ Install
zodand@hookform/resolvers - ✅ Use
zodResolverwithuseForm
Next Steps
For detailed guidance on specific tasks:
- COMPONENT_GUIDE.md - Deep dive into each component
- FORMS_GUIDE.md - Building complex forms
- PATTERNS.md - Common UI patterns and combinations
- CUSTOMIZATION.md - Theming and styling guide