skills/moderndegree/agent-skills/shadcn-best-practices

shadcn-best-practices

SKILL.md

shadcn/ui Best Practices

This skill covers best practices for working with shadcn/ui — component imports, className utilities, form building, theming, and data tables.

Use-When

This skill activates when:

  • Agent works with shadcn/ui components
  • Agent adds or imports shadcn components
  • Agent builds forms with validation
  • Agent configures theming or dark mode
  • Agent creates data tables

Core Rules

  • ALWAYS import shadcn components from @/components/ui/{component-name}
  • ALWAYS use the cn() utility for className merging
  • ALWAYS use Zod + React Hook Form for form validation
  • ALWAYS use CSS variables for theming (not hardcoded colors)
  • ALWAYS use TanStack Table for data tables
  • ALWAYS check components.json to identify the primitive library (Radix vs Base UI)
  • ALWAYS use migration commands when upgrading between styles (migrate radix, migrate rtl)

Common Agent Mistakes

  • Using relative paths instead of alias paths
  • Forgetting to import cn() utility
  • Hardcoding colors instead of using CSS variables
  • Building table logic manually instead of using TanStack Table
  • Assuming all shadcn projects use Radix UI (Base UI is now available)
  • Using Radix-specific imports in Base UI projects (or vice versa)

Examples

✅ Correct

import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"

function MyComponent({ className }) {
  return (
    <Button className={cn("base-class", className)}>
      <Input placeholder="Enter email" />
    </Button>
  )
}

❌ Wrong

// Using relative paths
import { Button } from "../../components/ui/button"

// Hardcoding colors
<Button className="bg-blue-500 text-white" />

// Building table manually
data.map(item => <tr><td>{item.name}</td></tr>)

// Assuming Radix - wrong for Base UI projects
import * as DialogPrimitive from "@radix-ui/react-dialog"

Identifying Primitive Library

// Check components.json to determine which library the project uses
// Look for "style" field:
// - "base-*" styles use @base-ui/react
// - Other styles use @radix-ui/react-* or radix-ui

// Example: reading the config
// import fs from "fs"
// const config = JSON.parse(fs.readFileSync("components.json", "utf-8"))
// config.style === "base-vega" // true = Base UI, false = Radix

// The API is identical regardless of library
import { Dialog, DialogContent } from "@/components/ui/dialog"
// Works the same for both Radix and Base UI projects

References

Weekly Installs
5
First Seen
Feb 17, 2026
Installed on
opencode5
gemini-cli5
github-copilot5
codex5
kimi-cli5
amp5