home / skills / shipshitdev / library / shadcn-setup

This skill sets up shadcn/ui with Tailwind v4 in Next.js projects, ensuring CSS-first configuration, theme tokens, and proper dependencies.

npx playbooks add skill shipshitdev/library --skill shadcn-setup

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
9.7 KB
---
name: shadcn-setup
description: Set up shadcn/ui component library with Tailwind CSS v4 configuration. Handles installation, initialization, theme configuration, and common component setup. Use when starting a new Next.js/React project that needs a component library.
version: 1.0.0
tags:
  - shadcn
  - ui
  - components
  - tailwind
  - react
  - nextjs
---

# shadcn/ui Setup

Sets up shadcn/ui with proper Tailwind CSS v4 configuration. This skill ensures you get the modern CSS-first setup, not the deprecated v3 approach.

## Purpose

**IMPORTANT**: shadcn/ui CLI and AI assistants often generate Tailwind v3 configs by default. This skill ensures:

- Tailwind v4 CSS-first configuration
- Proper `@theme` block with shadcn color tokens
- No deprecated `tailwind.config.js` files
- Correct dependency versions

## When to Use

- Setting up a new Next.js project with shadcn/ui
- Adding shadcn/ui to an existing project
- Migrating from shadcn + Tailwind v3 to v4
- Resetting a broken shadcn configuration

## Quick Start

```bash
# Full setup (recommended)
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root .

# With specific theme
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root . --theme zinc

# Install specific components
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root . --components button,card,input,dialog

# Next.js App Router (default)
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root . --app-router

# Next.js Pages Router
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root . --pages-router
```

## What Gets Installed

### Dependencies

```json
{
  "dependencies": {
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.0",
    "tailwind-merge": "^2.2.0",
    "lucide-react": "^0.400.0"
  },
  "devDependencies": {
    "tailwindcss": "^4.0.0",
    "@tailwindcss/postcss": "^4.0.0"
  }
}
```

### File Structure

```
project/
├── src/
│   ├── app/
│   │   └── globals.css           # Tailwind v4 + shadcn theme
│   ├── components/
│   │   └── ui/                   # shadcn components
│   │       ├── button.tsx
│   │       ├── card.tsx
│   │       └── ...
│   └── lib/
│       └── utils.ts              # cn() utility
├── components.json               # shadcn config
└── postcss.config.mjs            # PostCSS with @tailwindcss/postcss
```

## Tailwind v4 + shadcn CSS Configuration

The skill generates a CSS-first configuration:

```css
/* src/app/globals.css */
@import "tailwindcss";

@theme {
  /* Base colors */
  --color-background: hsl(0 0% 100%);
  --color-foreground: hsl(222.2 84% 4.9%);

  /* Card */
  --color-card: hsl(0 0% 100%);
  --color-card-foreground: hsl(222.2 84% 4.9%);

  /* Popover */
  --color-popover: hsl(0 0% 100%);
  --color-popover-foreground: hsl(222.2 84% 4.9%);

  /* Primary */
  --color-primary: hsl(222.2 47.4% 11.2%);
  --color-primary-foreground: hsl(210 40% 98%);

  /* Secondary */
  --color-secondary: hsl(210 40% 96.1%);
  --color-secondary-foreground: hsl(222.2 47.4% 11.2%);

  /* Muted */
  --color-muted: hsl(210 40% 96.1%);
  --color-muted-foreground: hsl(215.4 16.3% 46.9%);

  /* Accent */
  --color-accent: hsl(210 40% 96.1%);
  --color-accent-foreground: hsl(222.2 47.4% 11.2%);

  /* Destructive */
  --color-destructive: hsl(0 84.2% 60.2%);
  --color-destructive-foreground: hsl(210 40% 98%);

  /* Border & Input */
  --color-border: hsl(214.3 31.8% 91.4%);
  --color-input: hsl(214.3 31.8% 91.4%);
  --color-ring: hsl(222.2 84% 4.9%);

  /* Chart colors */
  --color-chart-1: hsl(12 76% 61%);
  --color-chart-2: hsl(173 58% 39%);
  --color-chart-3: hsl(197 37% 24%);
  --color-chart-4: hsl(43 74% 66%);
  --color-chart-5: hsl(27 87% 67%);

  /* Border radius */
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
  --radius-2xl: 1rem;
  --radius-full: 9999px;

  /* Sidebar (if using sidebar component) */
  --color-sidebar: hsl(0 0% 98%);
  --color-sidebar-foreground: hsl(240 5.3% 26.1%);
  --color-sidebar-primary: hsl(240 5.9% 10%);
  --color-sidebar-primary-foreground: hsl(0 0% 98%);
  --color-sidebar-accent: hsl(240 4.8% 95.9%);
  --color-sidebar-accent-foreground: hsl(240 5.9% 10%);
  --color-sidebar-border: hsl(220 13% 91%);
  --color-sidebar-ring: hsl(217.2 91.2% 59.8%);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  @theme {
    --color-background: hsl(222.2 84% 4.9%);
    --color-foreground: hsl(210 40% 98%);
    --color-card: hsl(222.2 84% 4.9%);
    --color-card-foreground: hsl(210 40% 98%);
    --color-popover: hsl(222.2 84% 4.9%);
    --color-popover-foreground: hsl(210 40% 98%);
    --color-primary: hsl(210 40% 98%);
    --color-primary-foreground: hsl(222.2 47.4% 11.2%);
    --color-secondary: hsl(217.2 32.6% 17.5%);
    --color-secondary-foreground: hsl(210 40% 98%);
    --color-muted: hsl(217.2 32.6% 17.5%);
    --color-muted-foreground: hsl(215 20.2% 65.1%);
    --color-accent: hsl(217.2 32.6% 17.5%);
    --color-accent-foreground: hsl(210 40% 98%);
    --color-destructive: hsl(0 62.8% 30.6%);
    --color-destructive-foreground: hsl(210 40% 98%);
    --color-border: hsl(217.2 32.6% 17.5%);
    --color-input: hsl(217.2 32.6% 17.5%);
    --color-ring: hsl(212.7 26.8% 83.9%);
    --color-sidebar: hsl(240 5.9% 10%);
    --color-sidebar-foreground: hsl(240 4.8% 95.9%);
    --color-sidebar-primary: hsl(224.3 76.3% 48%);
    --color-sidebar-primary-foreground: hsl(0 0% 100%);
    --color-sidebar-accent: hsl(240 3.7% 15.9%);
    --color-sidebar-accent-foreground: hsl(240 4.8% 95.9%);
    --color-sidebar-border: hsl(240 3.7% 15.9%);
  }
}

/* Base styles */
* {
  border-color: var(--color-border);
}

body {
  background-color: var(--color-background);
  color: var(--color-foreground);
}
```

## Available Themes

| Theme | Description |
|-------|-------------|
| `default` | shadcn default (neutral grays) |
| `zinc` | Zinc-based neutral |
| `slate` | Slate-based cool neutral |
| `stone` | Stone-based warm neutral |
| `gray` | Pure gray |
| `neutral` | True neutral |
| `red` | Red primary |
| `rose` | Rose primary |
| `orange` | Orange primary |
| `green` | Green primary |
| `blue` | Blue primary |
| `yellow` | Yellow primary |
| `violet` | Violet primary |

## Common Components

Install commonly used components:

```bash
# Essential set
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root . \
  --components button,card,input,label,dialog,dropdown-menu,toast

# Form-focused
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root . \
  --components form,input,label,select,checkbox,radio-group,switch,textarea

# Dashboard
python3 ~/.claude/skills/shadcn-setup/scripts/setup.py --root . \
  --components card,table,tabs,badge,avatar,dropdown-menu,sheet,sidebar
```

## components.json Configuration

```json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "src/app/globals.css",
    "baseColor": "zinc",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "iconLibrary": "lucide"
}
```

**Note**: The `tailwind.config` is empty because we use CSS-first configuration in v4.

## Utils File

```typescript
// src/lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

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

## Usage After Setup

### Adding Components

```bash
# Using bunx (recommended with bun)
bunx shadcn@latest add button

# Multiple components
bunx shadcn@latest add card dialog dropdown-menu
```

### Using Components

```tsx
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';

export function MyComponent() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Welcome</CardTitle>
      </CardHeader>
      <CardContent>
        <Button>Click me</Button>
      </CardContent>
    </Card>
  );
}
```

## Dark Mode Support

The CSS uses `prefers-color-scheme` by default. For manual toggle:

```tsx
// Add to layout.tsx or a theme provider
'use client';

import { useEffect, useState } from 'react';

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');

  useEffect(() => {
    document.documentElement.classList.toggle('dark', theme === 'dark');
  }, [theme]);

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}
```

Update CSS to use class-based dark mode:

```css
/* Replace @media (prefers-color-scheme: dark) with: */
.dark {
  --color-background: hsl(222.2 84% 4.9%);
  /* ... rest of dark theme variables */
}
```

## Troubleshooting

### "tailwind.config.js created by shadcn CLI"

Delete it. The CLI sometimes generates v3 configs. Run:

```bash
rm tailwind.config.js tailwind.config.ts
```

### Components not styled correctly

1. Check that `globals.css` is imported in your layout
2. Verify `@import "tailwindcss"` is at the top
3. Ensure `@theme` block contains all required variables

### Type errors with components

Run:

```bash
bun add -D @types/react @types/react-dom
```

### cn() utility not found

Create `src/lib/utils.ts`:

```typescript
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

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

## Validation

After setup, run the Tailwind v4 validator:

```bash
python3 ~/.claude/skills/tailwind4-validator/scripts/validate.py --root . --verbose
```

This ensures no v3 patterns were accidentally introduced.

Overview

This skill sets up the shadcn/ui component library with a Tailwind CSS v4 CSS-first configuration for Next.js or React projects. It automates installation, generates the v4-compatible globals.css with @theme tokens, wires common components, and ensures correct dependencies and postcss setup. Use it to avoid deprecated Tailwind v3 configs and to get a drop-in UI foundation with dark mode support.

How this skill works

The script installs required runtime and dev dependencies, creates a CSS-first globals.css that defines shadcn color tokens and radius variables, and places shadcn components under src/components/ui. It writes a components.json tailored for v4 (with an empty tailwind.config), generates a cn() utility using clsx + tailwind-merge, and optionally installs selected components. It also provides commands to validate the resulting Tailwind v4 configuration.

When to use it

  • Starting a new Next.js or React project that will use shadcn/ui
  • Adding shadcn/ui to an existing project and switching to Tailwind v4
  • Migrating a project that currently uses Tailwind v3 + shadcn to v4
  • Resetting or repairing a broken shadcn/Tailwind configuration
  • Scaffolding a common component set (buttons, cards, forms, dashboard)

Best practices

  • Run the full setup from your project root and commit the generated files before adding custom changes
  • Choose a base theme (default, zinc, slate, etc.) at install time to prefill CSS variables
  • Keep @import "tailwindcss" at the top of src/app/globals.css and ensure layout imports globals.css
  • Use the provided cn() utility (clsx + twMerge) to compose class names consistently
  • Delete any stray tailwind.config.js / tailwind.config.ts created by older tools to avoid v3 conflicts

Example use cases

  • Initialize a new Next.js App Router project with shadcn components and Tailwind v4 CSS-first theme
  • Add a focused form UI set (form, input, select, checkbox, textarea) to an existing app
  • Scaffold dashboard components (card, table, tabs, sidebar) for an admin interface
  • Migrate a legacy shadcn + Tailwind v3 setup to the v4 variables-based approach
  • Quickly enable dark mode by switching the media query theme block to a .dark class

FAQ

What if the shadcn CLI creates tailwind.config.js?

Delete tailwind.config.js or tailwind.config.ts and rerun the setup; the skill uses a CSS-first v4 approach so the config should be empty.

How do I enable manual theme toggle instead of prefers-color-scheme?

Replace the @media (prefers-color-scheme: dark) block with a .dark CSS block and toggle the .dark class on documentElement from a ThemeProvider.