DEV Community

Alex Spinov
Alex Spinov

Posted on

shadcn/ui Has a Free API That Is Redefining React Component Libraries

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
Enter fullscreen mode Exit fullscreen mode

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"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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} />
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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%;
  }
}
Enter fullscreen mode Exit fullscreen mode

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)