★ Featured
shadcn/ui + Radix UI Component Patterns
Build accessible component libraries with shadcn/ui, Radix primitives, and Tailwind CSS.
CLAUDE.md
# shadcn/ui + Radix UI Component Patterns
You are an expert in shadcn/ui, Radix UI primitives, Tailwind CSS, and accessible component design.
Architecture:
- shadcn/ui components are copied into your project, not installed as a package
- Components live in src/components/ui/ — you own and customize them
- Built on Radix UI primitives for accessibility + Tailwind for styling
- Use `npx shadcn@latest add <component>` to add new components
Component Patterns:
- Use `cn()` utility (clsx + tailwind-merge) for conditional class merging
- Forward refs with React.forwardRef for all base components
- Use `cva` (class-variance-authority) for variant-based component styling
- Define variants as a map: `{ variant: { default: '...', destructive: '...' }, size: { sm: '...', lg: '...' } }`
Radix Primitives:
- Dialog: use Dialog.Root, Dialog.Trigger, Dialog.Content — handles focus trap, escape, overlay click
- Popover: auto-positions with collision detection, handles outside click
- Select: fully keyboard navigable, screen reader announced
- Tabs: arrow key navigation between tabs, proper ARIA roles
- Toast: use a Toaster provider at app root, `toast()` function for imperative usage
Customization:
- Override component styles by editing the copied files directly
- Use CSS variables in globals.css for theme colors: `--primary`, `--background`, `--muted`
- Dark mode via `.dark` class on html element — all components auto-adapt
- Extend variants by adding new entries to the cva() definition
Forms:
- Use React Hook Form + Zod for validated forms
- `<FormField>` wraps Radix inputs with label, description, and error message
- Use `<FormMessage />` for inline validation errors
- Connect form state to UI: disabled submit while invalid, loading states
Best Practices:
- Never modify Radix primitive behavior — extend via composition
- Keep component API surface small: prefer composition over configuration
- Use `asChild` prop to merge Radix behavior onto custom elements
- Test keyboard navigation for every interactive component
- Use `data-[state=*]` selectors for styling based on Radix state
Add to your project root CLAUDE.md file, or append to an existing one.