shadcn/ui is not a component library — it's a collection of reusable components you copy into your project. And its CLI API is what makes it revolutionary.
The CLI: Components on Demand
# Initialize shadcn/ui in your project
npx shadcn@latest init
# Add specific components
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add data-table
npx shadcn@latest add command
# Add multiple at once
npx shadcn@latest add button card input label
Each component is copied into YOUR codebase — you own the code. No dependency lock-in.
The Registry API: Custom Component Collections
shadcn/ui's registry system lets you create and share component collections:
{
"$schema": "https://ui.shadcn.com/schema/registry.json",
"name": "my-components",
"type": "registry:ui",
"registryDependencies": ["button", "dialog"],
"dependencies": ["lucide-react"],
"files": [
{
"path": "ui/my-component.tsx",
"type": "registry:ui"
}
]
}
Data Table: Full-Featured Grid API
import { DataTable } from "@/components/ui/data-table";
import { ColumnDef } from "@tanstack/react-table";
const columns: ColumnDef<ScrapedData>[] = [
{
accessorKey: "url",
header: ({ column }) => (
<Button variant="ghost" onClick={() => column.toggleSorting()}>
URL <ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }) => <div className="max-w-[500px] truncate">{row.getValue("title")}</div>,
},
{
accessorKey: "price",
header: "Price",
cell: ({ row }) => {
const price = parseFloat(row.getValue("price"));
return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(price);
},
},
];
<DataTable columns={columns} data={scrapedProducts} />
Sorting, filtering, pagination, column visibility — all built-in.
Command Palette (cmdk)
import { Command } from "@/components/ui/command";
<Command>
<Command.Input placeholder="Search..." />
<Command.List>
<Command.Empty>No results found.</Command.Empty>
<Command.Group heading="Suggestions">
<Command.Item onSelect={() => navigate("/dashboard")}>Dashboard</Command.Item>
<Command.Item onSelect={() => navigate("/scrapers")}>My Scrapers</Command.Item>
</Command.Group>
<Command.Separator />
<Command.Group heading="Settings">
<Command.Item>Profile</Command.Item>
<Command.Item>API Keys</Command.Item>
</Command.Group>
</Command.List>
</Command>
Form Builder with React Hook Form + Zod
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Form, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
const form = useForm({ resolver: zodResolver(schema) });
<Form {...form}>
<FormField control={form.control} name="url" render={({ field }) => (
<FormItem>
<FormLabel>Target URL</FormLabel>
<Input placeholder="https://example.com" {...field} />
<FormMessage />
</FormItem>
)} />
</Form>
Theme API: CSS Variables
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
}
}
One CSS file controls your entire design system.
Need data for your shadcn/ui dashboards? My Apify scraping tools deliver structured data ready for your data tables.
Custom data pipeline? Email spinov001@gmail.com
Top comments (0)