Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
AI-powered UI styling skill with 67 UI styles and 161 reasoning rules for professional interface design.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/shadcn-theming.md
1# shadcn/ui Theming & Customization23Theme configuration, CSS variables, dark mode, and component customization.45## Dark Mode Setup67### Next.js App Router89**1. Install next-themes:**10```bash11npm install next-themes12```1314**2. Create theme provider:**15```tsx16// components/theme-provider.tsx17"use client"1819import * as React from "react"20import { ThemeProvider as NextThemesProvider } from "next-themes"2122export function ThemeProvider({23children,24...props25}: React.ComponentProps<typeof NextThemesProvider>) {26return <NextThemesProvider {...props}>{children}</NextThemesProvider>27}28```2930**3. Wrap app:**31```tsx32// app/layout.tsx33import { ThemeProvider } from "@/components/theme-provider"3435export default function RootLayout({ children }) {36return (37<html lang="en" suppressHydrationWarning>38<body>39<ThemeProvider40attribute="class"41defaultTheme="system"42enableSystem43disableTransitionOnChange44>45{children}46</ThemeProvider>47</body>48</html>49)50}51```5253**4. Theme toggle component:**54```tsx55import { Moon, Sun } from "lucide-react"56import { useTheme } from "next-themes"57import { Button } from "@/components/ui/button"5859export function ThemeToggle() {60const { setTheme, theme } = useTheme()6162return (63<Button64variant="ghost"65size="icon"66onClick={() => setTheme(theme === "light" ? "dark" : "light")}67>68<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />69<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />70<span className="sr-only">Toggle theme</span>71</Button>72)73}74```7576### Vite / Other Frameworks7778Use similar approach with next-themes or implement custom solution:7980```javascript81// Store preference82function toggleDarkMode() {83const isDark = document.documentElement.classList.toggle('dark')84localStorage.setItem('theme', isDark ? 'dark' : 'light')85}8687// Initialize on load88if (localStorage.theme === 'dark' ||89(!('theme' in localStorage) &&90window.matchMedia('(prefers-color-scheme: dark)').matches)) {91document.documentElement.classList.add('dark')92}93```9495## CSS Variable System9697shadcn/ui uses CSS variables for theming. Variables defined in `globals.css`:9899```css100@layer base {101:root {102--background: 0 0% 100%;103--foreground: 222.2 84% 4.9%;104--primary: 222.2 47.4% 11.2%;105--primary-foreground: 210 40% 98%;106--secondary: 210 40% 96.1%;107--secondary-foreground: 222.2 47.4% 11.2%;108--muted: 210 40% 96.1%;109--muted-foreground: 215.4 16.3% 46.9%;110--accent: 210 40% 96.1%;111--accent-foreground: 222.2 47.4% 11.2%;112--destructive: 0 84.2% 60.2%;113--destructive-foreground: 210 40% 98%;114--border: 214.3 31.8% 91.4%;115--input: 214.3 31.8% 91.4%;116--ring: 222.2 84% 4.9%;117--radius: 0.5rem;118}119120.dark {121--background: 222.2 84% 4.9%;122--foreground: 210 40% 98%;123--primary: 210 40% 98%;124--primary-foreground: 222.2 47.4% 11.2%;125--secondary: 217.2 32.6% 17.5%;126--secondary-foreground: 210 40% 98%;127--muted: 217.2 32.6% 17.5%;128--muted-foreground: 215 20.2% 65.1%;129--accent: 217.2 32.6% 17.5%;130--accent-foreground: 210 40% 98%;131--destructive: 0 62.8% 30.6%;132--destructive-foreground: 210 40% 98%;133--border: 217.2 32.6% 17.5%;134--input: 217.2 32.6% 17.5%;135--ring: 212.7 26.8% 83.9%;136}137}138```139140### Color Format141142Values use HSL format without `hsl()` wrapper for better opacity control:143```css144--primary: 222.2 47.4% 11.2%; /* H S L */145```146147Usage in Tailwind:148```css149background: hsl(var(--primary));150background: hsl(var(--primary) / 0.5); /* 50% opacity */151```152153## Tailwind Configuration154155Map CSS variables to Tailwind utilities:156157```ts158// tailwind.config.ts159export default {160darkMode: ["class"],161theme: {162extend: {163colors: {164border: "hsl(var(--border))",165input: "hsl(var(--input))",166ring: "hsl(var(--ring))",167background: "hsl(var(--background))",168foreground: "hsl(var(--foreground))",169primary: {170DEFAULT: "hsl(var(--primary))",171foreground: "hsl(var(--primary-foreground))",172},173secondary: {174DEFAULT: "hsl(var(--secondary))",175foreground: "hsl(var(--secondary-foreground))",176},177destructive: {178DEFAULT: "hsl(var(--destructive))",179foreground: "hsl(var(--destructive-foreground))",180},181muted: {182DEFAULT: "hsl(var(--muted))",183foreground: "hsl(var(--muted-foreground))",184},185accent: {186DEFAULT: "hsl(var(--accent))",187foreground: "hsl(var(--accent-foreground))",188},189},190borderRadius: {191lg: "var(--radius)",192md: "calc(var(--radius) - 2px)",193sm: "calc(var(--radius) - 4px)",194},195},196},197}198```199200## Color Customization201202### Method 1: Update CSS Variables203204Change colors by modifying CSS variables in `globals.css`:205206```css207:root {208--primary: 262.1 83.3% 57.8%; /* Purple */209--primary-foreground: 210 20% 98%;210}211212.dark {213--primary: 263.4 70% 50.4%; /* Darker purple */214--primary-foreground: 210 20% 98%;215}216```217218### Method 2: Theme Generator219220Use shadcn/ui theme generator: https://ui.shadcn.com/themes221222Select base color, generate theme, copy CSS variables.223224### Method 3: Multiple Themes225226Create theme variants with data attributes:227228```css229[data-theme="violet"] {230--primary: 262.1 83.3% 57.8%;231--primary-foreground: 210 20% 98%;232}233234[data-theme="rose"] {235--primary: 346.8 77.2% 49.8%;236--primary-foreground: 355.7 100% 97.3%;237}238```239240Apply theme:241```tsx242<div data-theme="violet">243<Button>Violet theme</Button>244</div>245```246247## Component Customization248249Components live in your codebase - modify directly.250251### Customize Variants252253```tsx254// components/ui/button.tsx255const buttonVariants = cva(256"inline-flex items-center justify-center rounded-md text-sm font-medium",257{258variants: {259variant: {260default: "bg-primary text-primary-foreground",261destructive: "bg-destructive text-destructive-foreground",262outline: "border border-input bg-background",263// Add custom variant264gradient: "bg-gradient-to-r from-purple-500 to-pink-500 text-white",265},266size: {267default: "h-10 px-4 py-2",268sm: "h-9 rounded-md px-3",269lg: "h-11 rounded-md px-8",270// Add custom size271xl: "h-14 rounded-md px-10 text-lg",272},273},274defaultVariants: {275variant: "default",276size: "default",277},278}279)280```281282Usage:283```tsx284<Button variant="gradient" size="xl">Custom Button</Button>285```286287### Customize Styles288289Modify base styles in component:290291```tsx292// components/ui/card.tsx293const Card = React.forwardRef<294HTMLDivElement,295React.HTMLAttributes<HTMLDivElement>296>(({ className, ...props }, ref) => (297<div298ref={ref}299className={cn(300"rounded-xl border bg-card text-card-foreground shadow-lg", // Modified301className302)}303{...props}304/>305))306```307308### Override with className309310Pass additional classes to override:311312```tsx313<Card className="border-2 border-purple-500 shadow-2xl hover:scale-105 transition-transform">314Custom styled card315</Card>316```317318## Base Color Presets319320shadcn/ui provides base color presets during `init`:321322- **Slate**: Cool gray tones323- **Gray**: Neutral gray324- **Zinc**: Warm gray325- **Neutral**: Balanced gray326- **Stone**: Earthy gray327328Select during setup or change later by updating CSS variables.329330## Style Variants331332Two component styles available:333334- **Default**: Softer, more rounded335- **New York**: Sharp, more contrast336337Select during `init` or in `components.json`:338339```json340{341"style": "new-york",342"tailwind": {343"cssVariables": true344}345}346```347348## Radius Customization349350Control border radius globally:351352```css353:root {354--radius: 0.5rem; /* Default */355--radius: 0rem; /* Sharp corners */356--radius: 1rem; /* Rounded */357}358```359360Components use radius variable:361```tsx362className="rounded-lg" /* Uses var(--radius) */363```364365## Best Practices3663671. **Use CSS Variables**: Enables runtime theme switching3682. **Consistent Foreground Colors**: Pair each color with appropriate foreground3693. **Test Both Themes**: Verify components in light and dark modes3704. **Semantic Naming**: Use `destructive` not `red`, `muted` not `gray`3715. **Accessibility**: Maintain sufficient color contrast (WCAG AA minimum)3726. **Component Overrides**: Use `className` prop for one-off customization3737. **Extract Patterns**: Create custom variants for repeated customizations374