shadcnui-customization-theming
Use this skill when customizing shadcn/ui themes, implementing dark mode, modifying component styles, or changing color schemes. Covers CSS variables, design tokens, theme generation, and component.json configuration. Assumes shadcn is already set up with components installed.
安装与使用
请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。
查看来源 ↗使用指南技能说明
shadcn/ui Customization & Theming
This skill covers customizing shadcn/ui components and implementing themes.
Prerequisites: Your project must have:
- Completed
shadcn initsetup - At least one component installed
-
components.jsonandsrc/lib/utils.tscreated - Tailwind CSS configured with CSS variables enabled
CSS Variables & Design Tokens
shadcn uses CSS variables to define the design system. After shadcn init, your global CSS file contains:
@import "tailwindcss";
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--muted: 221.2 63.6% 97.8%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 221.2 83.2% 53.3%;
--accent-foreground: 210 40% 98%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.3% 65.1%;
--accent: 221.2 83.2% 53.3%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 221.2 83.2% 53.3%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
Understanding CSS Variables
Each variable uses HSL format (Hue, Saturation, Lightness):
--accent: 221.2 83.2% 53.3%;
↑ ↑ ↑
hue sat light
- Hue: 0-360 (color)
- Saturation: 0-100% (intensity)
- Lightness: 0-100% (brightness)
Color Tokens
| Token | Purpose |
|---|---|
--background |
Default background color |
--foreground |
Default text color |
--card |
Card component background |
--card-foreground |
Card text color |
--muted |
Muted/disabled state background |
--muted-foreground |
Muted text color |
--accent |
Primary accent/highlight color |
--accent-foreground |
Text on accent backgrounds |
--destructive |
Destructive action color (red) |
--destructive-foreground |
Text on destructive backgrounds |
--border |
Border colors |
--input |
Input field background |
--ring |
Focus ring color |
--radius |
Default border radius |
Customizing Colors
To change a color, update the CSS variable value:
Change Primary Accent Color
:root {
--accent: 270 100% 50%; /* Changed from blue to purple */
}
.dark {
--accent: 270 100% 60%; /* Purple for dark mode */
}
Change All Backgrounds to Slightly Darker
:root {
--background: 0 0% 98%; /* Was 100%, slightly darker */
--card: 0 0% 98%;
--input: 214.3 31.8% 88%; /* Slightly darker input */
}
Monochrome Theme
:root {
--background: 0 0% 100%;
--foreground: 0 0% 0%;
--card: 0 0% 98%;
--card-foreground: 0 0% 0%;
--accent: 0 0% 20%; /* Dark gray accent */
--border: 0 0% 90%;
}
Dark Mode Implementation
After shadcn init, dark mode is configured with CSS variables. To toggle dark mode:
Using the dark class
Add the dark class to the root element to switch themes:
// src/App.tsx or root component
export function App() {
const [isDark, setIsDark] = useState(false)
return (
<div className={isDark ? 'dark' : ''}>
{/* Your app content */}
<button onClick={() => setIsDark(!isDark)}>
{isDark ? 'Light' : 'Dark'} Mode
</button>
</div>
)
}
Using next-themes (Recommended)
For persistent theme preference:
npm install next-themes
Setup in app entry:
// src/main.tsx or app/layout.tsx
import { ThemeProvider } from 'next-themes'
export default function App() {
return (
<ThemeProvider attribute="class" defaultTheme="system">
{/* Your app */}
</ThemeProvider>
)
}
Create theme toggle:
'use client'
import { useTheme } from 'next-themes'
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
{theme === 'dark' ? '☀️ Light' : '🌙 Dark'}
</button>
)
}
Customizing Component Styles
Since shadcn components are in your source code, modify them directly. No need for wrappers or overrides.
Example: Customize Button
Open src/components/ui/button.tsx:
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground hover:bg-primary/90",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
// Add custom variant
premium: "bg-gradient-to-r from-purple-600 to-blue-600 text-white hover:from-purple-700 hover:to-blue-700",
},
// Add custom size
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
xl: "h-14 rounded-lg px-6 text-lg",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
Now use the custom variant:
<Button variant="premium">Premium Button</Button>
<Button size="xl">Large Button</Button>
Example: Customize Card
Open src/components/ui/card.tsx and add styling:
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
// Add custom shadow or border
"rounded-lg border border-border/50 bg-card p-6 shadow-lg hover:shadow-xl transition-shadow",
className
)}
{...props}
/>
))
Custom Color Palette
Use the official theme generator: https://ui.shadcn.com/themes
- Visit the theme customizer
- Adjust colors visually
- Copy the generated CSS variables
- Paste into your global CSS
Adding Custom Components
Add your own components alongside shadcn components:
// src/components/ui/custom-button.tsx
import { Button } from './button'
export function CustomButton(props: React.ButtonHTMLAttributes<HTMLButtonElement>) {
return <Button {...props} className={`custom-class ${props.className}`} />
}
Responsive Design
shadcn uses Tailwind responsive classes. Customize spacing and sizing:
/* In your global CSS, customize default responsive values */
@layer base {
:root {
--radius: 0.5rem;
}
}
In components:
<div className="p-4 md:p-6 lg:p-8">
Responsive padding
</div>
Design System Best Practices
Consistent Spacing
Use Tailwind spacing scale:
<div className="space-y-4"> {/* 1rem gap between children */}
<Card>Item 1</Card>
<Card>Item 2</Card>
</div>
Consistent Typography
Tailwind predefined sizes:
<h1 className="text-4xl font-bold">Heading 1</h1>
<h2 className="text-2xl font-semibold">Heading 2</h2>
<p className="text-base text-muted-foreground">Body text</p>
Consistent Colors
Use design tokens, not hardcoded colors:
// ✅ Good - uses design tokens
<div className="bg-background text-foreground border border-border">Content</div>
// ❌ Avoid - hardcoded colors
<div className="bg-white text-black border border-gray-200">Content</div>
Configuration Reference
components.json
Customize how components are installed:
{
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true
},
"aliases": {
"@/components": "./src/components",
"@/lib/utils": "./src/lib/utils"
}
}
Key settings:
-
style- Visual design system (new-york, default) -
baseColor- Primary color palette (neutral, slate, gray, zinc, stone) -
cssVariables- Use CSS variables for theming (true recommended)
Common Customizations
Rounded Corners
:root {
--radius: 0.25rem; /* Sharper corners */
}
Or:
:root {
--radius: 1rem; /* More rounded */
}
Border Width
Add to button customization:
const buttonVariants = cva(
"border-2", // Thicker borders
// ... rest of styles
)
Font Family
In Tailwind config or global CSS:
@layer base {
body {
@apply font-sans; /* Uses Tailwind's sans font */
}
}
Troubleshooting
Styles not applying
Check:
- CSS variables exist in your global CSS file
- Global CSS is imported in your app entry
- Tailwind CSS is configured
- Component uses
classNameprop
Dark mode not toggling
Check:
- Provider is wrapping your app (if using next-themes)
-
darkclass is applied to root element - CSS variables for
.darktheme are defined
Custom colors not working
Check:
- Variables use correct HSL format:
hue saturation% lightness% - Variables are updated in both
:rootand.darkselectors - Components use
var(--your-variable)or Tailwind classes
Next Steps
Once theming is configured, you can:
- Build pages using styled components
- Implement advanced patterns (forms, tables, etc.)
- Create reusable component wrappers
For advanced patterns and complex features, see the patterns skill.
使用示例
查看来源仓库中的使用示例与配置说明。
查看来源 ↗来源历史
- 收录时间
- 2026-01-20
- 索引更新时间
- 2026-01-26
- Branch
- main
收录与同步日期属于本站记录。源码修改历史请查看来源仓库。
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!