- shadcn Component Review
- Systematic review process for ensuring custom components and layouts align with shadcn design patterns, official theme styles, and Radix UI best practices.
- Quick Start
- Planning Phase (Preventive)
- Before building a component:
- Check existing patterns
-
- Review similar components in
- src/ui/
- and
- src/components/
- Reference your theme style
-
- See
- references/theme-styles.md
- for spacing/shape patterns
- Use shadcn MCP
- (if available): Query components via shadcn MCP server
- Review checklist
-
- Use
- references/review-checklist.md
- as planning guide
- Review Phase (Post-Build)
- After building a component:
- Run spacing audit
-
- Check against your theme's spacing patterns
- Verify structure
-
- Ensure proper use of
- data-slot
- attributes and composition
- Check design tokens
-
- Verify semantic tokens only (no hardcoded colors)
- Test composability
-
- Ensure component can be reused and customized via props
- Validate responsive
-
- Test mobile-first approach and breakpoints
- Core Review Areas
- 1. Spacing (Theme-Dependent)
- Use
- gap-*
- for flex/grid containers. Spacing varies by theme style:
- Theme
- Spacing
- Shape
- Vega
- Standard
- Classic shadcn
- Nova
- Compact
- Reduced padding/margins
- Maia
- Generous
- Soft, rounded
- Lyra
- Standard
- Boxy, sharp
- Mira
- Dense
- Compact interfaces
- See
- references/theme-styles.md
- for theme-specific patterns.
- 2. Component Structure
- Use
- data-slot
- attributes:
- data-slot="component-name"
- Sub-components:
- ComponentName.Header
- ,
- ComponentName.Content
- Composition over modification (never edit
- src/ui/*
- directly)
- 3. Design Tokens
- Semantic tokens only -
- never
- hardcoded colors:
- // ✅ text-muted-foreground, bg-muted, hover:bg-accent
- // ❌ text-neutral-500, bg-gray-100, hover:bg-neutral-50
- 4. Composability
- Prop-based customization (variants, sizes)
- Slot-based composition (children, content blocks)
- Single responsibility, clear interface
- 5. Responsive Design
- Mobile-first (< 768px base)
- Breakpoints:
- md:
- (768px+),
- lg:
- (1024px+)
- Touch targets: min 44px
- Flex children:
- min-w-0
- to prevent overflow
- See
- references/review-checklist.md
- for detailed checklists.
- Foundational Patterns
- CVA (Class Variance Authority)
- shadcn components use CVA for type-safe, declarative variants:
- import
- {
- cva
- ,
- type
- VariantProps
- }
- from
- "class-variance-authority"
- const
- buttonVariants
- =
- cva
- (
- "inline-flex items-center justify-center font-medium transition-colors"
- ,
- {
- variants
- :
- {
- variant
- :
- {
- default
- :
- "bg-primary text-primary-foreground hover:bg-primary/90"
- ,
- outline
- :
- "border border-input bg-background hover:bg-accent"
- ,
- }
- ,
- size
- :
- {
- default
- :
- "h-9 px-4 py-2"
- ,
- sm
- :
- "h-8 px-3 text-sm"
- ,
- }
- ,
- }
- ,
- defaultVariants
- :
- {
- variant
- :
- "default"
- ,
- size
- :
- "default"
- }
- ,
- }
- )
- interface
- ButtonProps
- extends
- VariantProps
- <
- typeof
- buttonVariants
- >
- {
- }
- Key points:
- Base styles in first argument (always applied)
- Variants as declarative object
- Type-safe props via
- VariantProps
- Extend with new variants, don't modify base
- cn() Utility
- Always use
- cn()
- for conditional and override classes:
- import
- {
- cn
- }
- from
- "@/lib/utils"
- // Combines clsx (conditionals) + tailwind-merge (conflict resolution)
- <
- div
- className
- =
- {
- cn
- (
- "base-classes"
- ,
- isActive
- &&
- "active-classes"
- ,
- className
- // allows consumer overrides
- )
- }
- />
- Why it matters:
- Prevents CSS cascade conflicts
- Enables prop-based class overrides
- Handles conditional classes cleanly
- Theme-Aware Styling
- shadcn themes use CSS variables for consistent styling across components.
- Border radius
- is theme-defined via
- --radius
- :
- // ✅ Uses theme radius (adapts to Maia rounded vs Lyra sharp)
- <
- Button
- className
- =
- "
- rounded-md
- "
- >
- // Uses --radius variable
- <
- Card
- className
- =
- "
- rounded-lg
- "
- >
- // ❌ Hardcoded (ignores theme settings)
- <
- Button
- className
- =
- "
- rounded-[20px]
- "
- >
- Theme CSS variables
- (defined in your theme's CSS):
- --radius
- - Base radius unit
- --background
- ,
- --foreground
- - Base colors
- --primary
- ,
- --secondary
- ,
- --accent
- - Semantic colors
- --muted
- ,
- --card
- ,
- --popover
- - Surface colors
- Custom theme extensions
- If your project needs theme-switchable radius (e.g., pill vs sharp), create utility classes mapped to CSS variables:
/ Example: Theme-switchable radius /
.rounded-theme-button
{
border-radius
:
var
(
--radius-button
)
;
}
Animation Patterns
Use consistent, subtle animations. See
references/animation-patterns.md
for:
Timing standards (150ms fast, 200ms normal, 300ms slow)
Easing curves (ease-out for enter, ease-in for exit)
Radix
data-state
animation patterns
Framer Motion patterns for enter/exit
Accessibility (
motion-safe:
prefixes)
Resources
shadcn Documentation
Components
:
https://ui.shadcn.com/docs/components
Blocks
:
https://ui.shadcn.com/blocks
Themes
:
https://ui.shadcn.com/themes
Theme Creator
:
https://ui.shadcn.com/create
2025 Updates
Visual Styles
(via
npx shadcn create
):
Vega
- Classic shadcn/ui look
Nova
- Compact layouts, reduced spacing
Maia
- Soft and rounded, generous spacing
Lyra
- Boxy and sharp, pairs with mono fonts
Mira
- Dense interfaces
New utility components
:
input-group
/
button-group
- Grouped controls
empty
- Empty state patterns
field
- Form field wrapper
spinner
- Loading indicator
Technical updates
:
Full Tailwind v4 support (
@theme
directive)
OKLCH colors (from HSL)
React 19 compatibility
Community Tools
tweakcn
:
https://tweakcn.com/
- Interactive theme editor
Shadcn Studio
:
https://shadcnstudio.com/
- Theme generator
Shadcn Themer
:
https://shadcnthemer.com/
- Theme creator
Review Workflow
Step 1: Structure Review
Check component structure against shadcn patterns:
// ✅ Good: Proper structure with data-slot
<
div
data-slot
=
"
component-name
"
className
=
"
flex flex-col gap-4
"
< div data-slot = " component-header " className = " flex flex-col gap-2 "
{ / Header content / } </ div
< div data-slot = " component-content "
{ / Main content / } </ div
</ div
// ❌ Bad: Missing data-slot, inconsistent spacing < div className = " space-y-4 "
< div className = " mb-2 "
{ / Header content / } </ div
< div
{ / Main content / } </ div
</ div
Step 2: Spacing Audit Verify spacing follows your theme's patterns: Check all flex containers use gap- not space-y- or margins Verify spacing values follow Tailwind scale (2, 4, 6, 8, etc.) Ensure responsive spacing uses gap-X md:gap-Y pattern Match spacing density to your theme (Maia=generous, Nova/Mira=compact) Step 3: Design Token Check Verify semantic tokens only:
Check for hardcoded colors
grep -r "neutral-|gray-|slate-" [ component-file ] Step 4: Composability Review Ensure component can be: Reused in other contexts Customized via props (variants, sizes) Composed with other components Extended without modification Step 5: Responsive Verification Test at breakpoints: Mobile: 375px Tablet: 768px Desktop: 1280px Examples Good Component Pattern // ✅ Follows shadcn patterns export function PageContent ( { heading , description , contentBlock , children , } : PageContentProps ) { return ( < div data-slot = " page-content " className = " min-w-0 flex flex-col gap-4 md:gap-6 "
< div data-slot = " page-content-header " className = " flex flex-col gap-2 "
< h1 className = " text-xl md:text-2xl tracking-tight font-semibold text-foreground "
{ heading } </ h1
{ description && ( < p className = " text-sm text-muted-foreground "
{ description } </ p
) } </ div
{ contentBlock && ( < div data-slot = " page-content-block "
{ contentBlock } </ div
) } { children } </ div
) ; } Bad Component Pattern // ❌ Violates multiple patterns export function PageContent ( { heading , description } : Props ) { return ( < div className = " space-y-6 "
< div className = " mb-4 "
< h1 className = " text-2xl font-bold text-gray-900 "
{ heading } </ h1
< p className = " mt-2 text-sm text-neutral-500 "
{ description } </ p
</ div
</ div
) ; } Issues: Uses space-y- instead of gap- Hardcoded colors ( text-gray-900 , text-neutral-500 ) Missing data-slot attributes Inconsistent spacing ( mb-4 , mt-2 instead of flex gap) Additional Resources Theme Styles : references/theme-styles.md Review Checklist : references/review-checklist.md Animation Patterns : references/animation-patterns.md V2 Enhancement Ideas : references/v2-notes.md