All skills
google-labs-code avatar

/shadcn-ui

@29152aa official

Expert guidance for integrating and building applications with shadcn/ui components, including component discovery, installation, customization, and best practices.

Use this Skill: https://skilld.dev/gh/google-labs-code/stitch-skills/shadcn-ui

This session only. Nothing lands on disk.

resourcescustomization-guide.md

≈3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

shadcn/ui Customization Guide

Learn how to customize shadcn/ui components to match your brand and design requirements.

Theming Approach

shadcn/ui uses a CSS variable-based theming system, making it easy to customize colors, spacing, and other design tokens globally.

Color Customization

Understanding the Color System

shadcn/ui uses HSL color values stored as CSS variables. Each color has a base value and a foreground variant for text/content that appears on top of it.

Base Color Variables (in globals.css):

:root {
  --background: 0 0% 100%;        /* Page background */
  --foreground: 222.2 84% 4.9%;   /* Primary text color */
  --primary: 221.2 83.2% 53.3%;   /* Primary brand color */
  --primary-foreground: 210 40% 98%; /* Text on primary */
  --secondary: 210 40% 96.1%;     /* Secondary actions */
  --accent: 210 40% 96.1%;        /* Accent highlights */
  --muted: 210 40% 96.1%;         /* Muted backgrounds */
  --destructive: 0 84.2% 60.2%;   /* Error/danger */
  --border: 214.3 31.8% 91.4%;    /* Border colors */
  --input: 214.3 31.8% 91.4%;     /* Input borders */
  --ring: 221.2 83.2% 53.3%;      /* Focus rings */
}

Changing Brand Colors

To match your brand, update the primary color:

:root {
  /* Original blue */
  --primary: 221.2 83.2% 53.3%;
  
  /* Change to brand purple */
  --primary: 270 91% 65%;
  
  /* Adjust foreground for contrast */
  --primary-foreground: 0 0% 100%;
}

HSL Format: hue saturation lightness

  • Hue: 0-360 (color wheel position)
  • Saturation: 0-100% (color intensity)
  • Lightness: 0-100% (brightness)

Tools for Color Selection

  1. HSL Color Picker: https://hslpicker.com/
  2. Shadcn Theme Generator: https://ui.shadcn.com/themes
  3. Coolors: https://coolors.co/ (generates palettes)

Creating a Color Scheme

Start with your primary brand color, then derive other colors:

:root {
  /* 1. Primary brand color */
  --primary: 230 90% 60%;
  --primary-foreground: 0 0% 100%;
  
  /* 2. Lighter variant for secondary */
  --secondary: 230 30% 95%;
  --secondary-foreground: 230 90% 30%;
  
  /* 3. Subtle accent (shift hue slightly) */
  --accent: 200 90% 60%;
  --accent-foreground: 0 0% 100%;
  
  /* 4. Muted backgrounds (low saturation) */
  --muted: 230 20% 96%;
  --muted-foreground: 230 20% 40%;
  
  /* 5. Keep destructive red-based */
  --destructive: 0 84% 60%;
  --destructive-foreground: 0 0% 100%;
}

Dark Mode

Setting Up Dark Mode

shadcn/ui includes dark mode support out of the box. Add dark mode colors:

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --primary: 221.2 83.2% 53.3%;
  --primary-foreground: 210 40% 98%;
  /* ... all color variables */
}

Toggle Dark Mode

Next.js with next-themes:

npm install next-themes
// app/providers.tsx
"use client"

import { ThemeProvider } from "next-themes"

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
      {children}
    </ThemeProvider>
  )
}

// app/layout.tsx
import { Providers } from "./providers"

export default function RootLayout({ children }) {
  return (
    <html suppressHydrationWarning>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}

// components/theme-toggle.tsx
"use client"

import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"

export function ThemeToggle() {
  const { setTheme, theme } = useTheme()

  return (
    <Button
      variant="ghost"
      size="icon"
      onClick={() => setTheme(theme === "light" ? "dark" : "light")}
    >
      <Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
      <Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
      <span className="sr-only">Toggle theme</span>
    </Button>
  )
}

Component Customization

Using Variants

shadcn/ui components use class-variance-authority (cva) for variants. Example from Button:

// components/ui/button.tsx
import { cva, type VariantProps } from "class-variance-authority"

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

Adding Custom Variants

To add a new variant, edit the component file in components/ui/:

// Add new "success" variant to button
const buttonVariants = cva(
  "...",
  {
    variants: {
      variant: {
        default: "...",
        destructive: "...",
        // Add new variant
        success: "bg-green-600 text-white hover:bg-green-700",
      },
      // Add new size
      size: {
        default: "...",
        xl: "h-12 rounded-md px-10 text-base",
      },
    },
  }
)

// Update TypeScript interface
export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

Usage:

<Button variant="success" size="xl">Save Changes</Button>

Creating Composite Components

Don't modify components/ui/ directly. Instead, create wrapper components:

// components/loading-button.tsx
import { Button, ButtonProps } from "@/components/ui/button"
import { Loader2 } from "lucide-react"

interface LoadingButtonProps extends ButtonProps {
  loading?: boolean
}

export function LoadingButton({ 
  loading, 
  children, 
  disabled,
  ...props 
}: LoadingButtonProps) {
  return (
    <Button disabled={loading || disabled} {...props}>
      {loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
      {children}
    </Button>
  )
}

Typography Customization

Font Family

Update tailwind.config.js:

module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
        heading: ['Poppins', 'system-ui', 'sans-serif'],
        mono: ['Fira Code', 'monospace'],
      },
    },
  },
}

Import fonts in your layout:

// app/layout.tsx
import { Inter, Poppins } from 'next/font/google'

const inter = Inter({ subsets: ['latin'], variable: '--font-sans' })
const poppins = Poppins({ 
  weight: ['600', '700'], 
  subsets: ['latin'],
  variable: '--font-heading',
})

export default function RootLayout({ children }) {
  return (
    <html className={`${inter.variable} ${poppins.variable}`}>
      <body className="font-sans">{children}</body>
    </html>
  )
}

Use in components:

<h1 className="font-heading text-3xl">Heading</h1>
<p className="font-sans">Body text</p>

Font Sizes

Extend Tailwind's font scale:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      fontSize: {
        'xs': '0.75rem',     // 12px
        'sm': '0.875rem',    // 14px
        'base': '1rem',      // 16px
        'lg': '1.125rem',    // 18px
        'xl': '1.25rem',     // 20px
        '2xl': '1.5rem',     // 24px
        '3xl': '1.875rem',   // 30px
        '4xl': '2.25rem',    // 36px
        '5xl': '3rem',       // 48px
        '6xl': '3.75rem',    // 60px
        '7xl': '4.5rem',     // 72px
      },
    },
  },
}

Spacing & Layout

Border Radius

Customize roundedness globally:

/* globals.css */
:root {
  --radius: 0.5rem;  /* Default (8px) */
  
  /* More rounded */
  --radius: 1rem;    /* 16px */
  
  /* Sharp edges */
  --radius: 0;       /* No rounding */
  
  /* Very rounded */
  --radius: 1.5rem;  /* 24px */
}

This affects all components using rounded-lg, rounded-md, rounded-sm.

Custom Spacing

Extend Tailwind's spacing scale:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      spacing: {
        '72': '18rem',
        '84': '21rem',
        '96': '24rem',
      },
    },
  },
}

Animation Customization

Adjusting Existing Animations

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: {
        // Make accordion faster
        "accordion-down": {
          from: { height: 0 },
          to: { height: "var(--radix-accordion-content-height)" },
        },
        "accordion-up": {
          from: { height: "var(--radix-accordion-content-height)" },
          to: { height: 0 },
        },
      },
      animation: {
        "accordion-down": "accordion-down 0.15s ease-out", // Faster
        "accordion-up": "accordion-up 0.15s ease-out",
      },
    },
  },
}

Adding New Animations

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: {
        "fade-in": {
          "0%": { opacity: 0 },
          "100%": { opacity: 1 },
        },
        "slide-in-bottom": {
          "0%": { transform: "translateY(100%)" },
          "100%": { transform: "translateY(0)" },
        },
      },
      animation: {
        "fade-in": "fade-in 0.3s ease-out",
        "slide-in-bottom": "slide-in-bottom 0.3s ease-out",
      },
    },
  },
}

Use in components:

<div className="animate-fade-in">Content</div>

Advanced Customization

Creating a Design System

Structure your customizations:

src/
├── styles/
│   ├── globals.css          # CSS variables & base styles
│   ├── themes/
│   │   ├── default.css      # Default theme
│   │   └── brand.css        # Brand-specific overrides
│   └── components/
│       └── custom.css       # Component-specific styles
├── lib/
│   └── design-tokens.ts     # Shared constants
└── components/
    ├── ui/                  # shadcn components (don't modify)
    └── custom/              # Your wrapper components

Design Tokens File

// lib/design-tokens.ts
export const designTokens = {
  colors: {
    brand: {
      primary: 'hsl(230, 90%, 60%)',
      secondary: 'hsl(230, 30%, 95%)',
    },
  },
  spacing: {
    section: '5rem',
    card: '1.5rem',
  },
  radius: {
    card: '1rem',
    button: '0.5rem',
  },
  typography: {
    h1: 'text-5xl font-heading font-bold',
    h2: 'text-4xl font-heading font-semibold',
    h3: 'text-3xl font-heading font-semibold',
    body: 'text-base font-sans',
    small: 'text-sm text-muted-foreground',
  },
} as const

Use in components:

import { designTokens } from "@/lib/design-tokens"

<h1 className={designTokens.typography.h1}>Title</h1>

Best Practices

  1. Don't modify components/ui/ files directly: Create wrapper components instead
  2. Use CSS variables for theming: Easier to maintain and switch themes
  3. Leverage Tailwind's extend: Don't replace defaults, extend them
  4. Keep variants in component files: Co-locate variant logic with components
  5. Test dark mode: Ensure all customizations work in both themes
  6. Document custom variants: Add comments for custom additions
  7. Use consistent spacing: Stick to Tailwind's spacing scale
  8. Maintain accessibility: Don't sacrifice contrast for aesthetics

Resources

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides expert guidance for integrating shadcn/ui components into React applications. It uses standard MCP tools to fetch component source code and metadata from external registries and provides utility scripts to verify project configuration. A low-risk surface for indirect prompt injection exists as the skill processes external component code and data to perform filesystem operations.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    1/10 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 29152aa. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Steadyupdated 8 months ago
What it can do
Reads files Edits files Runs commands
All 6 allowed tools
shadcn*:*mcp_shadcn*ReadWriteBashweb_fetch

README badge

README badge for google-labs-code/stitch-skills/shadcn-ui

Provides expert guidance for discovering, installing, and customizing shadcn/ui components—a copy-paste component collection built on Radix UI or Base UI with Tailwind CSS. Helps with component discovery via MCP tools, theme customization through CSS variables, and best practices for extending components while maintaining accessibility.

Generated from the current SKILL.md.

Does this skill work with Base UI as well as Radix UI?
Yes. shadcn/ui components can use either Radix UI or Base UI primitives. The choice is configured during project initialization and components adapt to your selection.
Can I modify shadcn/ui components after installing them?
Yes. Components are copied into your codebase, giving you full ownership. You can modify styling, behavior, and structure freely without waiting for library updates.
What are the minimum dependencies required?
React 18+, Tailwind CSS 3.0+, either Radix UI or Base UI primitives, class-variance-authority, clsx, and tailwind-merge.
Does this skill help with form building?
Yes. The skill covers form patterns using shadcn/ui inputs, labels, and buttons, and recommends react-hook-form for validation.
Are shadcn/ui components accessible by default?
Yes. All components are built on Radix UI primitives, ensuring keyboard navigation, screen reader support, and proper ARIA attributes out of the box.

Generated from the current SKILL.md. These answers refresh after source changes.