Skip to content
Created: April 18, 2025

A quick overview of the basics of shadcn/ui (often colloquially called shad/ui) , bias Front-end engineering practice , suitable for people who already know React + Tailwind developers get started quickly.

1. What is shadcn/ui? ​

shadcn/ui ≠ component library

It is a component source code collection + CLI tool

Core features:

  • ✅ Not a black box component installed by npm
  • ✅ Copy the component code directly into your project
  • ✅ Based on Radix UI (no style, high accessibility)
  • ✅ Use Tailwind CSS to write styles
  • ✅ Highly customizable and maintainable

In one sentence:

You own the component instead of relying on a component library

2. Core technology stack ​

TechnologyFunction
ReactComponent System
Radix UIAccessible interaction logic (Dialog / Dropdown / Popover, etc.)
Tailwind CSSStyle System
class-variance-authority (CVA)Component variant management
lucide-reactdefault icon
clsx + tailwind-mergeclassName merge

3. Installation and initialization (core process) ​

bash
npx shadcn@latest init

Things you will do:

  1. Check if you have Tailwind

  2. Generate configuration file components.json

  3. Create directory:

    components/
      ui/
    lib/
      utils.ts

4. Where do the components come from? ​

bash
npx shadcn@latest add button

Result:

components/ui/button.tsx

👉 Source code directly into your project

tsx
// components/ui/button.tsx
const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground",
        outline: "border border-input bg-background",
      },
      size: {
        sm: "h-9 px-3",
        lg: "h-11 px-8",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "sm",
    },
  }
)

5. CVA (Core Focus) ​

The soul of shadcn/ui

1️⃣ Why not use a bunch of classNames? ​

❌ Bad way:

tsx
<button className={`
  px-4 py-2
  ${primary && "bg-blue-500"}
  ${size === "lg" && "text-lg"}
`} />

✅ shadcn/ui:

tsx
<Button variant="outline" size="lg" />

2️⃣ CVA principle ​

ts
const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md font-medium",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground",
        outline: "border border-input",
        ghost: "hover:bg-accent",
      },
      size: {
        sm: "h-9 px-3",
        md: "h-10 px-4",
        lg: "h-11 px-8",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "md",
    },
  }
)

Finally:

ts
buttonVariants({ variant: "outline", size: "lg" })

6. The role of Radix UI ​

Radix offers:

  • keyboard accessibility
  • focus management
  • ARIA
  • behavioral logic

For example Dialog:

tsx
<Dialog>
  <DialogTrigger>Open</DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Title</DialogTitle>
    </DialogHeader>
  </DialogContent>
</Dialog>

What shadcn/ui does:

  • Give Radix component Set Tailwind style
  • Unify API style

7. Theme system (CSS Variables) ​

shadcn/ui Don’t hardcode colors

css
:root {
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
}

When using:

tsx
bg-primary text-primary-foreground

Advantages:

  • 🌗 Natural support for dark mode
  • 🎨Theme switching cost is extremely low

8. Common directory structures ​

txt
components/
  ui/
    button.tsx
    dialog.tsx
    dropdown-menu.tsx
lib/
  utils.ts   // cn() 工具函数

utils.ts:

ts
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

9. Use paradigm (very important) ​

1️⃣ Composition instead of inheritance ​

tsx
<Button asChild>
  <Link href="/login">Login</Link>
</Button>

asChild is based on Radix Slot

2️⃣ Do not change the UI component logic ​

❌

tsx
components/ui/button.tsx

✅

tsx
components/common/submit-button.tsx

10. What projects is it suitable for? ​

  • ✅ Medium to large React / Next.js projects
  • ✅ Design System / Design System
  • ❌ Not suitable for novice projects that “install and use”

11. To what extent do you know how to learn? ​

You can do:

  • Understand the shadcn/ui component source code
  • Write a component with CVA yourself
  • Encapsulating business components based on Radix
  • Customize the theme instead of changing the class

12. Learning path suggestions (give you an advanced route) ​

  1. Familiar with Button/Input/Dialog source code
  2. Learn CVA
  3. Dive into Radix (Dialog/Popover/Dropdown)
  4. Encapsulate a component yourself (eg: DataTable)
  5. Design a set of theme variables