askill
shadcn-ui

shadcn-uiSafety --Repository

Installs, configures, and implements shadcn/ui accessible React components. Use when setting up shadcn/ui, adding components, building forms with React Hook Form and Zod, customising themes, or implementing UI patterns like buttons, dialogs, tables, and data displays.

2 stars
1.2k downloads
Updated 2/13/2026

Package Files

Loading files...
SKILL.md

shadcn/ui Component Guide

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

When to Use

  • Setting up a new project with shadcn/ui
  • Installing or configuring components
  • Building forms with React Hook Form and Zod
  • Creating accessible UI (buttons, dialogs, dropdowns, sheets)
  • Customising themes with Tailwind CSS variables
  • Implementing design systems

MCP Tools (Preferred Workflow)

Use the shadcn MCP tools as the primary method for component discovery and installation. Fall back to CLI commands only when MCP tools are unavailable.

Discovery Workflow

  1. Check project registries: Call mcp__shadcn__get_project_registries to verify components.json exists
  2. Search for components: Call mcp__shadcn__search_items_in_registries with the registry and query
  3. View component details: Call mcp__shadcn__view_items_in_registries to see source code and dependencies
  4. Get usage examples: Call mcp__shadcn__get_item_examples_from_registries for implementation patterns
  5. Get install command: Call mcp__shadcn__get_add_command_for_items for the exact CLI command

MCP Tool Reference

ToolPurpose
get_project_registriesCheck configured registries from components.json
search_items_in_registriesFuzzy search for components by name/description
list_items_in_registriesList all available components in a registry
view_items_in_registriesView source code, types, and dependencies
get_item_examples_from_registriesGet usage examples for components
get_add_command_for_itemsGet the CLI install command for components
get_audit_checklistGet accessibility and quality audit checklist
  1. Search: search_items_in_registries(registries: ["@shadcn"], query: "date picker")
  2. View: view_items_in_registries(items: ["@shadcn/date-picker"])
  3. Examples: get_item_examples_from_registries(items: ["@shadcn/date-picker"])
  4. Install: get_add_command_for_items(items: ["@shadcn/date-picker"])

CLI Commands

Quick Start

New project:

npx create-next-app@latest my-app --typescript --tailwind --eslint --app
cd my-app
npx shadcn@latest init
npx shadcn@latest add button input form card dialog select

Existing project:

npx shadcn@latest init

CLI Reference

CommandPurpose
npx shadcn@latest initInitialise shadcn/ui in a project
npx shadcn@latest add <component>Add a component
npx shadcn@latest add --allAdd all components
npx shadcn@latest search <query>Search registries
npx shadcn@latest listList available components
npx shadcn@latest view <component>View a component before installing
npx shadcn@latest buildGenerate registry JSON files
npx shadcn@latest migrateRun project migrations

See references/cli-reference.md for framework-specific installation and registry configuration.

Setup Verification Checklist

After initialisation, verify the setup works:

Setup Verification:
- [ ] `components.json` exists in project root
- [ ] `@/components/ui/` directory created
- [ ] `@/lib/utils.ts` contains the `cn` function
- [ ] `globals.css` has CSS variables for theming
- [ ] `tailwind.config` includes shadcn colour tokens
- [ ] Test: `npx shadcn@latest add button` installs without errors
- [ ] Test: Import and render `<Button>` compiles without errors

Component Quick Reference

ComponentInstallKey Props
Buttonadd buttonvariant, size, asChild
Inputadd inputtype, placeholder, disabled
Formadd formReact Hook Form + Zod integration
Cardadd cardCardHeader, CardContent, CardFooter
Dialogadd dialogDialogTrigger, DialogContent
Selectadd selectSelectTrigger, SelectContent, SelectItem
Sheetadd sheetside="left|right|top|bottom"
Toastadd toastuseToast() hook, variant
Tableadd tableTableHeader, TableBody, TableRow

Install all: npx shadcn@latest add --all

Core Patterns

Button Variants

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

// Variants: default, destructive, outline, secondary, ghost, link
<Button variant="destructive">Delete</Button>

// Sizes: default, sm, lg, icon
<Button size="icon"><Trash className="h-4 w-4" /></Button>

// Loading state
<Button disabled>
  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
  Loading
</Button>

Form with Validation

"use client"

import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import * as 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(),
  password: z.string().min(8),
})

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 control={form.control} name="email" render={({ field }) => (
          <FormItem>
            <FormLabel>Email</FormLabel>
            <FormControl><Input type="email" {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <FormField control={form.control} name="password" render={({ field }) => (
          <FormItem>
            <FormLabel>Password</FormLabel>
            <FormControl><Input type="password" {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <Button type="submit">Login</Button>
      </form>
    </Form>
  )
}

Dialog (Modal)

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

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline">Open</Button>
  </DialogTrigger>
  <DialogContent className="sm:max-w-[425px]">
    <DialogHeader>
      <DialogTitle>Edit profile</DialogTitle>
      <DialogDescription>Make changes here.</DialogDescription>
    </DialogHeader>
    <div className="py-4">{/* Content */}</div>
    <DialogFooter>
      <Button type="submit">Save</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Toast Notifications

Add <Toaster /> to the root layout once (see references/nextjs-integration.md), then call useToast anywhere:

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." })

Theming

Customise via CSS variables in globals.css:

:root {
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
  --radius: 0.5rem;
}
.dark {
  --primary: 210 40% 98%;
  --primary-foreground: 222.2 47.4% 11.2%;
}

See references/configuration.md for complete config files (TSConfig, Tailwind, CSS variables, dependencies).

Best Practices

  1. Verify accessibility: Run get_audit_checklist after adding components. Check keyboard navigation and screen reader output.
  2. Validate with Zod: Define a Zod schema for every form. Pass it to zodResolver in useForm.
  3. Use cn() for all class merging: Never concatenate class strings manually. cn() resolves Tailwind conflicts.
  4. Keep server components default: Only add "use client" when the component uses hooks, event handlers, or browser APIs. See references/nextjs-integration.md.
  5. Theme with CSS variables: Change colours in globals.css :root and .dark blocks. Do not hardcode colour values in components.
async function onSubmit(values: z.infer<typeof formSchema>) {
  try {
    const res = await fetch("/api/submit", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(values),
    })
    if (!res.ok) {
      const data = await res.json()
      toast({ variant: "destructive", title: "Submission failed", description: data.message ?? "Check your input and try again." })
      return
    }
    toast({ title: "Saved", description: "Your changes have been saved." })
    form.reset()
  } catch {
    toast({ variant: "destructive", title: "Network error", description: "Could not reach the server. Try again later." })
  }
}

References

All detailed documentation is in references/:

FileContent
configuration.mdTSConfig, Tailwind config, CSS variables, dependencies
nextjs-integration.mdApp Router, Server Components, API routes
advanced-patterns.mdComplex forms, custom variants, dialog with forms, sheet nav
cli-reference.mdAll CLI commands, framework installs, registries
extended-components.mdTerminal, Dock, Credit Card, QR Code, charts, animations, hooks
learning-guide.mdLearning path, exercises, CVA and cn patterns

External Links:

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

AI review pending.

Metadata

Licenseunknown
Version-
Updated2/13/2026
Publishercosta-marcello

Tags

apici-cdgithub-actionstesting