31 lines | 1.7 KB

shadcn/ui conventions

You own the components

  • shadcn/ui is open code copied into your project, not a runtime dependency. The components live in components/ui and you edit them.
  • Customize in place. Don't build a wrapper layer around them or try to npm install the components.
  • Add with the CLI: npx shadcn@latest add button dialog … (run npx shadcn@latest init once to scaffold components.json + @/lib/utils).

Styling

  • Merge classes with cn() from @/lib/utils (clsx + tailwind-merge). Never concatenate class strings by hand — cn() resolves Tailwind conflicts.
  • Define variants with cva (class-variance-authority) and surface them via props (e.g. variant, size). One component, many variants — not many components.
  • Forward className and spread ...props so callers can extend a component without forking it.

Radix + accessibility

  • Components are built on Radix primitives — keep their structure (Trigger / Content / Portal) and data-[state=…] styling hooks intact.
  • Interactive components are client components: keep the "use client" directive. Use lucide-react for icons.

Theming

  • Use semantic tokens (bg-background, text-foreground, text-muted-foreground, border-input, ring), driven by CSS variables — not raw color utilities like bg-zinc-900.
  • Keep light/dark in the CSS variables; don't branch colors in component logic.

Anti-patterns

  • ❌ Re-publishing components/ui as an internal package instead of editing in place.
  • `px-2 ${cond ? "bg-red-500" : ""}` instead of cn("px-2", cond && "bg-red-500").
  • ❌ Hardcoded hex/bg-*-500 colors that bypass the theme tokens.
  • ❌ Dropping Radix sub-parts or "use client" and reimplementing primitives by hand.