DEV Community

Alex Spinov
Alex Spinov

Posted on

shadcn/ui Has a Free API You're Not Using

shadcn/ui is not a component library — it's a CLI that copies components into your codebase. But most developers just use npx shadcn add button and miss the powerful customization APIs.

The Free APIs You're Missing

1. CLI — Intelligent Component Installation

# Add component with all dependencies
npx shadcn@latest add dialog

# Add multiple at once
npx shadcn@latest add button card input label

# See what would be added (diff mode)
npx shadcn@latest diff dialog

# Update component to latest version
npx shadcn@latest diff
Enter fullscreen mode Exit fullscreen mode

The CLI resolves dependencies, adds required packages, and never overwrites your customizations.

2. components.json — Full Customization

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "src/app/globals.css",
    "baseColor": "zinc",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Custom Themes — CSS Variable System

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 240 10% 3.9%;
    --primary: 240 5.9% 10%;
    --primary-foreground: 0 0% 98%;
    --ring: 240 5.9% 10%;
    --radius: 0.5rem;
  }
  .dark {
    --background: 240 10% 3.9%;
    --foreground: 0 0% 98%;
    --primary: 0 0% 98%;
    --primary-foreground: 240 5.9% 10%;
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Compound Components — Extend with Composition

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

// Create domain-specific components from primitives
function ConfirmDialog({ title, onConfirm, children }) {
  return (
    <Dialog>
      <DialogTrigger asChild>{children}</DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
        </DialogHeader>
        <div className="flex justify-end gap-2">
          <Button variant="outline">Cancel</Button>
          <Button variant="destructive" onClick={onConfirm}>Confirm</Button>
        </div>
      </DialogContent>
    </Dialog>
  );
}
Enter fullscreen mode Exit fullscreen mode

5. Data Table — Full-Featured Table Component

import { DataTable } from "@/components/ui/data-table";
import { ColumnDef } from "@tanstack/react-table";

const columns: ColumnDef<User>[] = [
  { accessorKey: "name", header: "Name" },
  { accessorKey: "email", header: "Email" },
  {
    id: "actions",
    cell: ({ row }) => <UserActions user={row.original} />,
  },
];

<DataTable columns={columns} data={users} />
Enter fullscreen mode Exit fullscreen mode

Sorting, filtering, pagination, row selection — all type-safe.

Getting Started

npx shadcn@latest init
npx shadcn@latest add button
Enter fullscreen mode Exit fullscreen mode

Need data from any website delivered as clean JSON? I build production web scrapers that handle anti-bot, proxies, and rate limits. 77 scrapers running in production. Email me: Spinov001@gmail.com

Check out my awesome-web-scraping list for the best scraping tools and resources.

Top comments (0)