Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
aia-11-hn-mib avatar

Shadcn Ui

  • 4 installs
  • 1 repo stars
  • Updated November 15, 2025
  • aia-11-hn-mib/mib-mockinterviewaibot

shadcn-ui is a Claude Code skill for implementing shadcn/ui, a collection of accessible React components built with Radix UI and Tailwind CSS and distributed via CLI.

About

This skill guides implementing shadcn/ui, a collection of accessible React components built with Radix UI and Tailwind CSS and distributed via CLI rather than npm. It covers CLI and manual setup, components.json config, adding components, forms with React Hook Form and Zod, and dark-mode theming. A developer uses it when building React interfaces or a design system. It documents the copy-into-your-project ownership model.

  • Implements shadcn/ui components built on Radix UI and Tailwind
  • Copy-paste, CLI-distributed components you fully own
  • Covers setup, forms with React Hook Form + Zod, and theming

Shadcn Ui by the numbers

  • 4 all-time installs (skills.sh)
  • Ranked #1,810 of 2,244 Frontend Development skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

shadcn-ui capabilities & compatibility

Free; shadcn/ui components are open source and copied into your project.

Capabilities
ui components · design system · form building · theming
Use cases
frontend · ui design · web design
IDEs
vscode · cursor ide
Pricing
Free
From the docs

What shadcn-ui says it does

shadcn/ui is a collection of beautifully-designed, accessible components and a code distribution platform built with TypeScript, Tailwind CSS, and Radix UI primitives.
SKILL.md
Components distributed via CLI, not npm packages
SKILL.md
npx skills add https://github.com/aia-11-hn-mib/mib-mockinterviewaibot --skill shadcn-ui

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs4
repo stars1
Last updatedNovember 15, 2025
Repositoryaia-11-hn-mib/mib-mockinterviewaibot

What it does

Set up and add accessible shadcn/ui components with Tailwind and Radix UI in React-based apps, including forms and theming.

Who is it for?

Adding accessible, ownable UI components and design systems to React apps

When should I use this skill?

Building React interfaces, adding UI components, or implementing a Tailwind design system

What you get

shadcn/ui components installed, themed, and composed in a React app.

  • Configured shadcn/ui setup
  • Added UI components
  • Forms with validation

By the numbers

  • Built on 3 core technologies (TypeScript, Tailwind CSS, Radix UI)

Files

SKILL.mdMarkdownGitHub ↗

shadcn/ui Skill

shadcn/ui is a collection of beautifully-designed, accessible components and a code distribution platform built with TypeScript, Tailwind CSS, and Radix UI primitives. It's not a traditional component library but a collection of reusable components you can copy and paste into your apps.

Reference

https://ui.shadcn.com/llms.txt

When to Use This Skill

Use this skill when:

  • Building user interfaces with React-based frameworks (Next.js, Vite, Remix, Astro, etc.)
  • Adding pre-built, accessible UI components to applications
  • Implementing design systems with Tailwind CSS
  • Setting up forms with validation (React Hook Form + Zod)
  • Adding data tables, charts, or complex UI patterns
  • Implementing dark mode with consistent theming
  • Customizing component appearance and behavior

Core Concepts

Key Principles

  • Open Code: Copy components into your project, modify freely
  • Composition: Built with composable primitives from Radix UI
  • Distribution: Components distributed via CLI, not npm packages
  • Beautiful Defaults: Thoughtfully designed with excellent aesthetics
  • AI-Ready: Structured for easy integration with AI tools

Architecture

shadcn/ui follows a unique distribution model: 1. CLI Tool: Installs and manages components via npx shadcn@latest 2. Component Registry: Central repository of components 3. Local Components: Components live in your components/ui/ directory 4. Full Ownership: You own the code, modify as needed

Technology Stack

  • TypeScript: Full type safety
  • Tailwind CSS: Utility-first styling (v3 and v4 support)
  • Radix UI: Accessible, unstyled primitives
  • Class Variance Authority: Component variants
  • React 19: Compatible with latest React

Installation & Setup

Initial Setup

Using the CLI (Recommended):

npx shadcn@latest init

The CLI will prompt for:

  • Framework preference (Next.js, Vite, etc.)
  • TypeScript or JavaScript
  • Component installation location
  • CSS variables or Tailwind configuration
  • Color theme preferences
  • Global CSS file location

Manual Setup:

1. Install dependencies:

npm install tailwindcss-animate class-variance-authority clsx tailwind-merge lucide-react

2. Create components.json:

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css",
    "baseColor": "zinc",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils"
  }
}

3. Configure Tailwind:

// tailwind.config.ts
import type { Config } from "tailwindcss"

const config: Config = {
  darkMode: ["class"],
  content: [
    './pages/**/*.{ts,tsx}',
    './components/**/*.{ts,tsx}',
    './app/**/*.{ts,tsx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [require("tailwindcss-animate")],
}

export default config

4. Create utility file:

// lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Adding Components

Via CLI:

# Add single component
npx shadcn@latest add button

# Add multiple components
npx shadcn@latest add button card dialog

# Add all components
npx shadcn@latest add --all

What happens when you add a component: 1. Component files are copied to components/ui/ 2. Dependencies are automatically installed 3. Component is ready to import and use

Component Categories

Form & Input Components

Button:

import { Button } from "@/components/ui/button"

<Button variant="default">Click me</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline" size="sm">Small</Button>
<Button variant="ghost" size="icon">
  <Icon />
</Button>

Input:

import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

<div>
  <Label htmlFor="email">Email</Label>
  <Input id="email" type="email" placeholder="you@example.com" />
</div>

Form (with validation):

import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"

const formSchema = z.object({
  username: z.string().min(2).max(50),
  email: z.string().email(),
})

function ProfileForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      username: "",
      email: "",
    },
  })

  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="username"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Username</FormLabel>
              <FormControl>
                <Input placeholder="shadcn" {...field} />
              </FormControl>
              <FormDescription>
                This is your public display name.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>
  )
}

Select:

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"

<Select>
  <SelectTrigger className="w-[180px]">
    <SelectValue placeholder="Theme" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="light">Light</SelectItem>
    <SelectItem value="dark">Dark</SelectItem>
    <SelectItem value="system">System</SelectItem>
  </SelectContent>
</Select>

Checkbox:

import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"

<div className="flex items-center space-x-2">
  <Checkbox id="terms" />
  <Label htmlFor="terms">Accept terms and conditions</Label>
</div>

Date Picker:

import { Calendar } from "@/components/ui/calendar"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { Button } from "@/components/ui/button"
import { CalendarIcon } from "lucide-react"
import { format } from "date-fns"

const [date, setDate] = useState<Date>()

<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline">
      <CalendarIcon className="mr-2 h-4 w-4" />
      {date ? format(date, "PPP") : "Pick a date"}
    </Button>
  </PopoverTrigger>
  <PopoverContent className="w-auto p-0">
    <Calendar mode="single" selected={date} onSelect={setDate} />
  </PopoverContent>
</Popover>

Layout & Navigation

Card:

import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"

<Card>
  <CardHeader>
    <CardTitle>Card Title</CardTitle>
    <CardDescription>Card Description</CardDescription>
  </CardHeader>
  <CardContent>
    <p>Card Content</p>
  </CardContent>
  <CardFooter>
    <p>Card Footer</p>
  </CardFooter>
</Card>

Tabs:

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

<Tabs defaultValue="account">
  <TabsList>
    <TabsTrigger value="account">Account</TabsTrigger>
    <TabsTrigger value="password">Password</TabsTrigger>
  </TabsList>
  <TabsContent value="account">Account settings</TabsContent>
  <TabsContent value="password">Password settings</TabsContent>
</Tabs>

Accordion:

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion"

<Accordion type="single" collapsible>
  <AccordionItem value="item-1">
    <AccordionTrigger>Is it accessible?</AccordionTrigger>
    <AccordionContent>
      Yes. It adheres to the WAI-ARIA design pattern.
    </AccordionContent>
  </AccordionItem>
</Accordion>

Navigation Menu:

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"

<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Item One</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLink>Link</NavigationMenuLink>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>

Overlays & Dialogs

Dialog:

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"

<Dialog>
  <DialogTrigger asChild>
    <Button>Open Dialog</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Are you sure?</DialogTitle>
      <DialogDescription>
        This action cannot be undone.
      </DialogDescription>
    </DialogHeader>
  </DialogContent>
</Dialog>

Drawer:

import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

<Drawer>
  <DrawerTrigger>Open</DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Are you sure?</DrawerTitle>
      <DrawerDescription>This action cannot be undone.</DrawerDescription>
    </DrawerHeader>
    <DrawerFooter>
      <Button>Submit</Button>
      <DrawerClose>Cancel</DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>

Popover:

import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"

<Popover>
  <PopoverTrigger>Open</PopoverTrigger>
  <PopoverContent>Place content here.</PopoverContent>
</Popover>

Toast:

import { useToast } from "@/hooks/use-toast"
import { Button } from "@/components/ui/button"

const { toast } = useToast()

<Button
  onClick={() => {
    toast({
      title: "Scheduled: Catch up",
      description: "Friday, February 10, 2023 at 5:57 PM",
    })
  }}
>
  Show Toast
</Button>

Command:

import {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command"

<Command>
  <CommandInput placeholder="Type a command or search..." />
  <CommandList>
    <CommandEmpty>No results found.</CommandEmpty>
    <CommandGroup heading="Suggestions">
      <CommandItem>Calendar</CommandItem>
      <CommandItem>Search Emoji</CommandItem>
      <CommandItem>Calculator</CommandItem>
    </CommandGroup>
  </CommandList>
</Command>

Feedback & Status

Alert:

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"

<Alert>
  <AlertTitle>Heads up!</AlertTitle>
  <AlertDescription>
    You can add components to your app using the CLI.
  </AlertDescription>
</Alert>

<Alert variant="destructive">
  <AlertTitle>Error</AlertTitle>
  <AlertDescription>
    Your session has expired. Please log in again.
  </AlertDescription>
</Alert>

Progress:

import { Progress } from "@/components/ui/progress"

<Progress value={33} />

Skeleton:

import { Skeleton } from "@/components/ui/skeleton"

<div className="flex items-center space-x-4">
  <Skeleton className="h-12 w-12 rounded-full" />
  <div className="space-y-2">
    <Skeleton className="h-4 w-[250px]" />
    <Skeleton className="h-4 w-[200px]" />
  </div>
</div>

Display Components

Table:

import {
  Table,
  TableBody,
  TableCaption,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"

<Table>
  <TableCaption>A list of your recent invoices.</TableCaption>
  <TableHeader>
    <TableRow>
      <TableHead>Invoice</TableHead>
      <TableHead>Status</TableHead>
      <TableHead>Amount</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>INV001</TableCell>
      <TableCell>Paid</TableCell>
      <TableCell>$250.00</TableCell>
    </TableRow>
  </TableBody>
</Table>

Data Table (with sorting/filtering):

npx shadcn@latest add data-table

Avatar:

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

<Avatar>
  <AvatarImage src="https://github.com/shadcn.png" />
  <AvatarFallback>CN</AvatarFallback>
</Avatar>

Badge:

import { Badge } from "@/components/ui/badge"

<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>

Theming & Customization

Dark Mode Setup

Next.js (App Router):

1. Install next-themes:

npm install next-themes

2. Create theme provider:

// components/theme-provider.tsx
"use client"

import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"

export function ThemeProvider({
  children,
  ...props
}: React.ComponentProps<typeof NextThemesProvider>) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}

3. Wrap app with provider:

// app/layout.tsx
import { ThemeProvider } from "@/components/theme-provider"

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

4. Add theme toggle:

import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"

export function ThemeToggle() {
  const { setTheme, theme } = useTheme()

  return (
    <Button
      variant="ghost"
      size="icon"
      onClick={() => setTheme(theme === "light" ? "dark" : "light")}
    >
      <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
      <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
      <span className="sr-only">Toggle theme</span>
    </Button>
  )
}

Color Customization

Using CSS Variables:

/* globals.css */
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;
    /* ... */
  }
}

Using Tailwind Config:

// tailwind.config.ts
export default {
  theme: {
    extend: {
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        // ...
      },
    },
  },
}

Component Customization

Since components live in your codebase, you can modify them directly:

// components/ui/button.tsx
// Modify variants, add new ones, change styles
const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground",
        destructive: "bg-destructive text-destructive-foreground",
        outline: "border border-input bg-background",
        // Add custom variant
        custom: "bg-gradient-to-r from-purple-500 to-pink-500 text-white",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        // Add custom size
        xl: "h-14 rounded-md px-10 text-lg",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

Advanced Patterns

Server Actions (Next.js)

// app/actions.ts
"use server"

import { z } from "zod"

const schema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
})

export async function createUser(formData: FormData) {
  const validatedFields = schema.safeParse({
    email: formData.get("email"),
    password: formData.get("password"),
  })

  if (!validatedFields.success) {
    return {
      errors: validatedFields.error.flatten().fieldErrors,
    }
  }

  // Create user
}

// app/signup/page.tsx
import { createUser } from "@/app/actions"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"

export default function SignupPage() {
  return (
    <form action={createUser}>
      <Input name="email" type="email" />
      <Input name="password" type="password" />
      <Button type="submit">Sign up</Button>
    </form>
  )
}

Reusable Form Patterns

// lib/form-utils.ts
import { UseFormReturn } from "react-hook-form"
import { FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"

export function TextFormField({
  form,
  name,
  label,
  placeholder,
  type = "text",
}: {
  form: UseFormReturn<any>
  name: string
  label: string
  placeholder?: string
  type?: string
}) {
  return (
    <FormField
      control={form.control}
      name={name}
      render={({ field }) => (
        <FormItem>
          <FormLabel>{label}</FormLabel>
          <FormControl>
            <Input type={type} placeholder={placeholder} {...field} />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />
  )
}

Responsive Component Composition

import { useMediaQuery } from "@/hooks/use-media-query"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import { Drawer, DrawerContent } from "@/components/ui/drawer"

export function ResponsiveDialog({ children, ...props }) {
  const isDesktop = useMediaQuery("(min-width: 768px)")

  if (isDesktop) {
    return (
      <Dialog {...props}>
        <DialogContent>{children}</DialogContent>
      </Dialog>
    )
  }

  return (
    <Drawer {...props}>
      <DrawerContent>{children}</DrawerContent>
    </Drawer>
  )
}

Best Practices

1. Use TypeScript: Leverage full type safety for better DX 2. Customize Components: Modify components directly in your codebase 3. Compose Primitives: Build complex UIs by composing simple components 4. Follow Accessibility: Components are built on accessible Radix UI primitives 5. Use Form Validation: Integrate React Hook Form + Zod for robust forms 6. Dark Mode: Implement theme switching for better UX 7. Responsive Design: Use Tailwind responsive utilities 8. Performance: Use code splitting and lazy loading for large component sets 9. Consistent Spacing: Use Tailwind spacing scale consistently 10. Icon Library: Use lucide-react for consistent icons

Framework-Specific Setup

Next.js

  • Support for App Router and Pages Router
  • Server Components compatibility
  • Server Actions integration

Vite

  • Fast development with HMR
  • Easy setup with TypeScript

Remix

  • Route-based architecture
  • Progressive enhancement

Astro

  • Static site generation
  • Islands architecture

Laravel (Inertia.js)

  • Backend integration with Laravel
  • React frontend with Inertia

Common Patterns

Loading States

import { Skeleton } from "@/components/ui/skeleton"

export function UserCardSkeleton() {
  return (
    <div className="flex items-center space-x-4">
      <Skeleton className="h-12 w-12 rounded-full" />
      <div className="space-y-2">
        <Skeleton className="h-4 w-[250px]" />
        <Skeleton className="h-4 w-[200px]" />
      </div>
    </div>
  )
}

export function UserCard({ user }: { user?: User }) {
  if (!user) return <UserCardSkeleton />

  return (
    <div className="flex items-center space-x-4">
      <Avatar>
        <AvatarImage src={user.avatar} />
        <AvatarFallback>{user.initials}</AvatarFallback>
      </Avatar>
      <div>
        <p className="text-sm font-medium">{user.name}</p>
        <p className="text-sm text-muted-foreground">{user.email}</p>
      </div>
    </div>
  )
}

Error Handling

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { AlertCircle } from "lucide-react"

export function ErrorAlert({ error }: { error: Error }) {
  return (
    <Alert variant="destructive">
      <AlertCircle className="h-4 w-4" />
      <AlertTitle>Error</AlertTitle>
      <AlertDescription>{error.message}</AlertDescription>
    </Alert>
  )
}

Confirmation Dialogs

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"

export function DeleteConfirmation({ onConfirm }: { onConfirm: () => void }) {
  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button variant="destructive">Delete</Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
          <AlertDialogDescription>
            This action cannot be undone. This will permanently delete your
            account and remove your data from our servers.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction onClick={onConfirm}>Continue</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Troubleshooting

Common Issues

1. "Module not found" errors

  • Check path aliases in tsconfig.json
  • Verify components.json aliases match your project structure
  • Ensure components are installed in correct directory

2. Styling not applied

  • Verify Tailwind CSS is configured correctly
  • Check globals.css imports CSS variables
  • Ensure tailwindcss-animate plugin is installed

3. Dark mode not working

  • Check ThemeProvider is wrapping your app
  • Verify suppressHydrationWarning on <html> tag
  • Ensure dark mode classes are defined in CSS

4. Form validation issues

  • Install required packages: react-hook-form, @hookform/resolvers, zod
  • Check schema matches form fields
  • Verify resolver is configured correctly

5. TypeScript errors

  • Update @types/react and @types/react-dom
  • Check component prop types
  • Ensure TypeScript version is compatible (>= 4.5)

Resources

  • Documentation: https://ui.shadcn.com
  • GitHub: https://github.com/shadcn-ui/ui
  • Component Registry: https://ui.shadcn.com/docs/components
  • Examples: https://ui.shadcn.com/examples
  • Figma Design Kit: https://ui.shadcn.com/figma
  • v0 (AI UI Generator): https://v0.dev

Implementation Checklist

When implementing shadcn/ui:

  • [ ] Run npx shadcn@latest init to set up project
  • [ ] Configure Tailwind CSS and path aliases
  • [ ] Set up dark mode with ThemeProvider
  • [ ] Install required components via CLI
  • [ ] Create utility functions (cn helper)
  • [ ] Set up form handling (React Hook Form + Zod)
  • [ ] Configure icons (lucide-react)
  • [ ] Implement theme toggle component
  • [ ] Test components in both light and dark modes
  • [ ] Customize color palette if needed
  • [ ] Add loading states with Skeleton
  • [ ] Implement error handling patterns
  • [ ] Test accessibility features
  • [ ] Optimize bundle size (tree-shaking)
  • [ ] Add responsive design utilities

Related skills

Forks & variants (1)

Shadcn Ui has 1 known copy in the catalog totaling 3 installs. They canonicalize to this original listing.

FAQ

Is shadcn/ui an npm component library?

No, it is distributed via CLI and you copy components into your components/ui directory and own the code.

What is it built on?

TypeScript, Tailwind CSS, and Radix UI primitives.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.