Shadcn ui
Skill ComeOnOliver/skillshub/skills/TerminalSkills/skills/shadcn-ui
π§ The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.
npx -y skills add ComeOnOliver/skillshub --skill shadcn-uiAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
6.1 KB, as published. Nobody here has run it
shadcn/ui β Copy-Paste Component Library
You are an expert in shadcn/ui, the collection of reusable React components built with Radix UI and Tailwind CSS. You help developers build beautiful, accessible interfaces by copying components directly into their project (not installed as a dependency) β providing full ownership and customization of every component including buttons, dialogs, forms, tables, command palettes, toasts, and 40+ primitives.
Core Capabilities
Installation and Usage
# Initialize in your project
npx shadcn@latest init
# Add components (copies source code into your project)
npx shadcn@latest add button dialog card input form table
npx shadcn@latest add command toast dropdown-menu sheet tabs
# Components are now in your project at components/ui/
// Full ownership β edit anything
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
const schema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Invalid email"),
});
function CreateUserDialog() {
const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
defaultValues: { name: "", email: "" },
});
return (
<Dialog>
<DialogTrigger asChild>
<Button>Add User</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create User</DialogTitle>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField control={form.control} name="name" render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl><Input placeholder="John Doe" {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="email" render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl><Input placeholder="[email protected]" {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<Button type="submit" className="w-full">Create</Button>
</form>
</Form>
</DialogContent>
</Dialog>
);
}
Data Table
import { DataTable } from "@/components/ui/data-table";
import { ColumnDef } from "@tanstack/react-table";
import { Badge } from "@/components/ui/badge";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { MoreHorizontal } from "lucide-react";
const columns: ColumnDef<User>[] = [
{ accessorKey: "name", header: "Name" },
{ accessorKey: "email", header: "Email" },
{
accessorKey: "role",
header: "Role",
cell: ({ row }) => <Badge variant={row.original.role === "admin" ? "default" : "secondary"}>{row.original.role}</Badge>,
},
{
id: "actions",
cell: ({ row }) => (
<DropdownMenu>
<DropdownMenuTrigger asChild><Button variant="ghost" size="icon"><MoreHorizontal className="h-4 w-4" /></Button></DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => editUser(row.original)}>Edit</DropdownMenuItem>
<DropdownMenuItem className="text-red-600" onClick={() => deleteUser(row.original.id)}>Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
),
},
];
function UsersPage() {
return <DataTable columns={columns} data={users} searchKey="name" />;
}
Command Palette
import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
function CommandPalette() {
const [open, setOpen] = useState(false);
useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); setOpen(true); }
};
document.addEventListener("keydown", down);
return () => document.removeEventListener("keydown", down);
}, []);
return (
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Actions">
<CommandItem onSelect={() => navigate("/dashboard")}>π Dashboard</CommandItem>
<CommandItem onSelect={() => navigate("/settings")}>βοΈ Settings</CommandItem>
<CommandItem onSelect={() => createNewProject()}>β New Project</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>
);
}
Installation
npx shadcn@latest init # Setup (adds tailwind config, utils, etc.)
npx shadcn@latest add [component] # Add specific components
Best Practices
- Not a dependency β Components are copied into your project; you own the code, customize freely
- Radix primitives β Built on Radix UI; fully accessible (ARIA, keyboard navigation) out of the box
- Tailwind styling β All styles via Tailwind classes; customize with your design tokens in
globals.css - Variant system β Uses
class-variance-authority(cva) for component variants; extend with your own - Form integration β
Formcomponent wraps react-hook-form + zod; type-safe validation built-in - Theme β CSS variables in
globals.css; switch light/dark by changing variables;next-themesfor toggle - Composition β Components are composable primitives; build complex UIs by combining simple parts
- Registry β Browse all components at ui.shadcn.com; preview before adding to your project