shadcn-ui

Complete guide to building accessible React components with shadcn/ui, Radix UI, and Tailwind CSS. Install and configure components via CLI ( npx shadcn@latest add ), then customize directly in your project since you own the code Covers 10+ core components: buttons, inputs, forms with Zod validation, cards, dialogs, dropdowns, sheets, tables, toasts, and charts built on Recharts Full Next.js App Router integration with Server Components, form handling, and metadata support; all components use "use client" directive Theme with CSS variables for light/dark modes; extend Tailwind config for custom colors, spacing, and animations

INSTALLATION
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill shadcn-ui
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

shadcn/ui Component Patterns

Build accessible, customizable UI components with shadcn/ui, Radix UI, and Tailwind CSS.

Overview

  • Components are copied into your project — you own and customize the code
  • Built on Radix UI primitives for full accessibility
  • Styled with Tailwind CSS and CSS variables for theming
  • CLI-based installation: npx shadcn@latest add <component>

When to Use

Activate when user requests involve:

  • "Set up shadcn/ui", "initialize shadcn", "add shadcn components"
  • "Install button/input/form/dialog/card/select/toast/table/chart"
  • "React Hook Form", "Zod validation", "form with validation"
  • "accessible components", "Radix UI", "Tailwind theme"
  • "shadcn button", "shadcn dialog", "shadcn sheet", "shadcn table"
  • "dark mode", "CSS variables", "custom theme"
  • "charts with Recharts", "bar chart", "line chart", "pie chart"

Quick Reference

Available Components

Component

Install Command

Description

button

npx shadcn@latest add button

Variants: default, destructive, outline, secondary, ghost, link

input

npx shadcn@latest add input

Text input field

form

npx shadcn@latest add form

React Hook Form integration with validation

card

npx shadcn@latest add card

Container with header, content, footer

dialog

npx shadcn@latest add dialog

Modal overlay

sheet

npx shadcn@latest add sheet

Slide-over panel (top/right/bottom/left)

select

npx shadcn@latest add select

Dropdown select

toast

npx shadcn@latest add toast

Notification toasts

table

npx shadcn@latest add table

Data table

menubar

npx shadcn@latest add menubar

Desktop-style menubar

chart

npx shadcn@latest add chart

Recharts wrapper with theming

textarea

npx shadcn@latest add textarea

Multi-line text input

checkbox

npx shadcn@latest add checkbox

Checkbox input

label

npx shadcn@latest add label

Accessible form label

Instructions

Initialize Project

# New Next.js project

npx create-next-app@latest my-app --typescript --tailwind --eslint --app

cd my-app

npx shadcn@latest init

# Existing project

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

npx shadcn@latest init

# Install components

npx shadcn@latest add button input form card dialog select toast

Basic Component Usage

// Button with variants and sizes

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

<Button variant="default">Default</Button>

<Button variant="destructive" size="sm">Delete</Button>

<Button variant="outline" disabled>Loading...</Button>

Form with Zod Validation

"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 formSchema = z.object({

  email: z.string().email("Invalid email"),

  password: z.string().min(8, "Password must be at least 8 characters"),

})

export function LoginForm() {

  const form = useForm<z.infer<typeof formSchema>>({

    resolver: zodResolver(formSchema),

    defaultValues: { email: "", password: "" },

  })

  return (

    <Form {...form}>

      <form onSubmit={form.handleSubmit(console.log)} className="space-y-4">

        <FormField name="email" control={form.control} render={({ field }) => (

          <FormItem>

            <FormLabel>Email</FormLabel>

            <FormControl><Input type="email" {...field} /></FormControl>

            <FormMessage />

          </FormItem>

        )} />

        <FormField name="password" control={form.control} render={({ field }) => (

          <FormItem>

            <FormLabel>Password</FormLabel>

            <FormControl><Input type="password" {...field} /></FormControl>

            <FormMessage />

          </FormItem>

        )} />

        <Button type="submit">Login</Button>

      </form>

    </Form>

  )

}

See references/forms-and-validation.md for advanced multi-field forms, contact forms with API submission, and login card patterns.

Dialog (Modal)

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

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

<Dialog>

  <DialogTrigger asChild>

    <Button variant="outline">Open</Button>

  </DialogTrigger>

  <DialogContent>

    <DialogHeader>

      <DialogTitle>Edit Profile</DialogTitle>

    </DialogHeader>

    {/* content */}

  </DialogContent>

</Dialog>

Toast Notification

// 1. Add <Toaster /> to app/layout.tsx

import { Toaster } from "@/components/ui/toaster"

// 2. Use in components

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

const { toast } = useToast()

toast({ title: "Success", description: "Changes saved." })

toast({ variant: "destructive", title: "Error", description: "Something went wrong." })

Bar Chart

import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"

import { ChartContainer, ChartTooltipContent } from "@/components/ui/chart"

const chartConfig = {

  desktop: { label: "Desktop", color: "var(--chart-1)" },

} satisfies import("@/components/ui/chart").ChartConfig

<ChartContainer config={chartConfig} className="min-h-[200px] w-full">

  <BarChart data={data}>

    <CartesianGrid vertical={false} />

    <XAxis dataKey="month" />

    <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />

    <ChartTooltip content={<ChartTooltipContent />} />

  </BarChart>

</ChartContainer>

See references/charts-components.md for Line, Area, and Pie chart examples.

Examples

Login Form with Validation

"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 formSchema = z.object({

  email: z.string().email("Invalid email"),

  password: z.string().min(8, "Min 8 characters"),

})

export function LoginForm() {

  const form = useForm<z.infer<typeof formSchema>>({

    resolver: zodResolver(formSchema),

    defaultValues: { email: "", password: "" },

  })

  return (

    <Form {...form}>

      <form onSubmit={form.handleSubmit(console.log)} className="space-y-4">

        <FormField name="email" control={form.control} render={({ field }) => (

          <FormItem>

            <FormLabel>Email</FormLabel>

            <FormControl><Input type="email" {...field} /></FormControl>

            <FormMessage />

          </FormItem>

        )} />

        <FormField name="password" control={form.control} render={({ field }) => (

          <FormItem>

            <FormLabel>Password</FormLabel>

            <FormControl><Input type="password" {...field} /></FormControl>

            <FormMessage />

          </FormItem>

        )} />

        <Button type="submit">Login</Button>

      </form>

    </Form>

  )

}

Data Table with Actions

import { ColumnDef } from "@tanstack/react-table"

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

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

import { DataTable } from "@/components/ui/data-table"

const columns: ColumnDef<User>[] = [

  { id: "select", header: ({ table }) => (

    <Checkbox checked={table.getIsAllPageRowsSelected()} />

  ), cell: ({ row }) => (

    <Checkbox checked={row.getIsSelected()} />

  )},

  { accessorKey: "name", header: "Name" },

  { accessorKey: "email", header: "Email" },

  { id: "actions", cell: ({ row }) => (

    <Button variant="ghost" size="sm">Edit</Button>

  )},

]

Dialog with Form

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

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

<Dialog>

  <DialogTrigger asChild>

    <Button variant="outline">Add User</Button>

  </DialogTrigger>

  <DialogContent>

    <DialogHeader>

      <DialogTitle>Add New User</DialogTitle>

    </DialogHeader>

    {/* <LoginForm /> */}

  </DialogContent>

</Dialog>

Toast Notifications

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

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

const { toast } = useToast()

toast({ title: "Saved", description: "Changes saved successfully." })

toast({ variant: "destructive", title: "Error", description: "Failed to save." })

Best Practices

  • Accessibility: Use Radix UI primitives — ARIA attributes are built in
  • Client Components: Add "use client" for interactive components (hooks, events)
  • Type Safety: Use TypeScript and Zod schemas for form validation
  • Theming: Configure CSS variables in globals.css for consistent design
  • Customization: Modify component files directly — you own the code
  • Path Aliases: Ensure @ alias is configured in tsconfig.json
  • Registry Security: Only install components from trusted registries; review generated code before production use
  • Dark Mode: Set up with CSS variables strategy and next-themes
  • Forms: Always use Form, FormField, FormItem, FormLabel, FormMessage together
  • Toaster: Add <Toaster /> once to root layout

Constraints and Warnings

  • Not an NPM Package: Components are copied to your project; they are not a versioned dependency
  • Registry Security: Components from npx shadcn@latest add are fetched remotely; always verify the registry source is trusted before installation
  • Client Components: Most interactive components require "use client" directive
  • Radix Dependencies: Ensure all @radix-ui packages are installed
  • Tailwind Required: Components rely on Tailwind CSS utilities
  • Path Aliases: Configure @ alias in tsconfig.json for imports

References

Consult these files for detailed patterns and code examples:

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card