
Design System Ui
- 1 installs
- 87 repo stars
- Updated July 22, 2026
- alibaba/opc-starter
Design System UI is a Claude Code skill that turns design references into Tailwind CSS and Shadcn UI frontend projects using a Mobile First strategy.
About
This skill converts design references or screenshots into Tailwind CSS and Shadcn UI frontend projects. A developer uses it to scaffold a new UI from a visual reference or to retrofit an existing project with a new theme. It defaults to a Mobile First responsive strategy and includes design-token extraction and self-verification steps.
- Turns design screenshots into Tailwind CSS + Shadcn UI projects
- Defaults to a Mobile First responsive strategy
- Can retrofit an existing project with a new theme
Design System Ui by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,609 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
design-system-ui capabilities & compatibility
- Capabilities
- design system · ui scaffolding · theme retrofit · design token extraction
- Use cases
- frontend · ui design · web design
What design-system-ui says it does
Create distinctive, production-grade frontend interfaces with high design quality using Mobile First strategy.
Transform design references into distinctive, production-ready Tailwind CSS + Shadcn UI projects.
npx skills add https://github.com/alibaba/opc-starter --skill design-system-uiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 87 |
| Last updated | July 22, 2026 |
| Repository | alibaba/opc-starter ↗ |
What it does
Generate a Tailwind CSS + Shadcn UI frontend from a design screenshot or restyle an existing project.
Who is it for?
Scaffolding or restyling a Tailwind + Shadcn UI frontend from a visual design reference
When should I use this skill?
You have a design screenshot or want to retrofit a project with a new Tailwind/Shadcn theme
What you get
A production-ready Tailwind CSS + Shadcn UI project or retrofitted theme derived from the reference.
- Tailwind CSS config
- Shadcn UI component setup
- Design tokens / theme
By the numbers
- 3 execution paths: new project, retrofit, and fix theme issues
- 4 project-template asset files (components.json, globals.css, utils.ts, tailwind.config.ts)
Files
Design System UI
For Claude Opus 4.5: This skill leverages your advanced reasoning and creative capabilities. Use the decision trees for rapid technical choices, and the checkpoints for self-verification.
Transform design references into distinctive, production-ready Tailwind CSS + Shadcn UI projects.
📱 Default Strategy: Mobile First — All new projects use Mobile First by default. Design for mobile viewport first, then progressively enhance for larger screens.
---
🧠 Execution Strategy
Before starting, determine your execution path:
┌─────────────────────────────────────────────────────────────────┐
│ DECISION: What type of task is this? │
├─────────────────────────────────────────────────────────────────┤
│ │
│ A) NEW PROJECT from design reference │
│ → Execute: Steps 0 → 1 → 2 → 3 → 4 → 5 → 6 │
│ → Focus: Creative interpretation + technical scaffolding │
│ → 📱 DEFAULT: Mobile First strategy │
│ │
│ B) RETROFIT existing project with new theme │
│ → Execute: Steps 0 → 3 → 7 → 7.5 → 8 → 9 → 10 → 11 │
│ → Focus: Systematic audit + replacement + verification │
│ → 📱 DETECT: Check for Mobile First → Ask if not found │
│ │
│ C) FIX theme/color issues in existing project │
│ → Execute: Troubleshooting section → targeted fixes │
│ → Focus: Diagnosis + minimal surgical changes │
│ │
└─────────────────────────────────────────────────────────────────┘Mobile First Strategy Decision Tree
┌─────────────────────────────────────────────────────────────────┐
│ 📱 MOBILE FIRST DETECTION (for Retrofit projects) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Run detection commands: │
│ grep -rn "sm:" src/ | head -20 │
│ grep -rn "md:" src/ | head -20 │
│ grep -rn "@media.*min-width" src/ | head -10 │
│ │
│ Analyze results: │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Mobile First indicators found? │ │
│ │ (Base styles for mobile, sm:/md:/lg: for larger screens) │ │
│ │ │ │
│ │ YES → Continue with Mobile First strategy │ │
│ │ Maintain and enhance existing patterns │ │
│ │ │ │
│ │ NO → Desktop First detected (max-width media queries) │ │
│ │ Or no responsive patterns at all │ │
│ │ → ASK USER: │ │
│ │ "是否需要将项目改造为 Mobile First 响应式策略? │ │
│ │ 这将优化移动端体验,但需要重构现有断点逻辑。" │ │
│ │ │ │
│ │ User says YES → Execute Mobile First Retrofit │ │
│ │ User says NO → Preserve existing responsive logic │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘Tool Usage Strategy
| Task | Primary Tools | Usage Pattern |
|---|---|---|
| Analyze design | read_file (image) | Read screenshot, extract tokens |
| Check Tailwind version | grep | grep '"tailwindcss"' package.json |
| Detect Mobile First | grep | `grep -rn "sm:\ |
| Audit hardcoded colors | grep | Pattern scan across src/ |
| Apply changes | search_replace | Targeted replacements |
| Verify changes | mcp_browser_* | Visual verification in browser |
---
🎨 Step 0: Creative Design Thinking
THINK: Before writing any code, pause and commit to a BOLD aesthetic direction.
Design Context Questions
| Dimension | Question | Your Answer |
|---|---|---|
| Purpose | What problem does this interface solve? Who uses it? | _Think this through_ |
| Tone | Which extreme aesthetic direction? (see library below) | _Commit to ONE_ |
| Differentiation | What makes this UNFORGETTABLE? | _Be specific_ |
| 📱 Mobile First | Design for mobile viewport first. How does this enhance UX? | _Default: YES_ |
📱 Mobile First Mindset
For NEW projects, always start with:
- Base styles = mobile viewport (< 640px)
sm:= small tablets (≥ 640px)md:= tablets/small laptops (≥ 768px)lg:= desktops (≥ 1024px)xl:/2xl:= large screens (≥ 1280px / ≥ 1536px)
// ✅ Mobile First (correct)
<div className="flex flex-col md:flex-row">
<div className="w-full md:w-1/2 lg:w-1/3">
<p className="text-sm md:text-base lg:text-lg">
// ❌ Desktop First (avoid)
<div className="flex flex-row md:flex-col"> // Adding mobile styles laterAesthetic Direction Library
Choose ONE and execute with conviction (bold maximalism and refined minimalism both work - the key is intentionality):
| Style | Characteristics | Use When |
|---|---|---|
| Brutally Minimal | Extreme whitespace, monochrome, no decoration | Developer tools, pro apps |
| Maximalist Chaos | Color explosion, complex layers, dense motion | Creative, entertainment |
| Retro-Futuristic | Cyberpunk, neon gradients, tech feel | Games, tech products |
| Luxury/Refined | Gold accents, serif fonts, exquisite details | Premium, finance |
| Playful/Toy-like | Rounded shapes, high saturation, bouncy motion | Children, social apps |
| Editorial/Magazine | Big type, grid systems, generous whitespace | Content, blogs |
| Brutalist/Raw | Thick borders, hard shadows, high contrast | Art, indie brands |
⚠️ Anti-Patterns (AI Slop)
NEVER use these defaults:
- Inter, Roboto, Arial, Space Grotesk as primary fonts
- Purple gradients on white backgrounds
- Cookie-cutter rounded corners everywhere
- Safe, middle-of-the-road color choices
---
Step 1: Analyze Design Reference
Accept input as: Screenshots, Figma exports, URLs, or verbal descriptions.
Extraction Checklist
Colors: Primary → Secondary → Accent → Neutral scale → Semantic
Typography: Display font → Body font → Weights → Sizes → Line heights
Spacing: Base unit → Component padding → Section margins
Visual: Border radius → Shadow style → Animation mood
Details: Gradients → Textures → Patterns → Overlays🔍 Self-Check: Design Analysis
Before proceeding, verify you have extracted:
- [ ] At least 5 distinct color values (primary, secondary, accent, muted, destructive)
- [ ] Font family choices that are NOT Inter/Roboto/Arial
- [ ] A clear visual mood direction
---
Step 2: Generate Design Tokens
Convert analysis into structured tokens. Use HSL format for Tailwind compatibility.
const designTokens = {
colors: {
primary: { DEFAULT: "hsl(H S% L%)", foreground: "hsl(...)" },
secondary: { DEFAULT: "hsl(...)", foreground: "hsl(...)" },
accent: { DEFAULT: "hsl(...)", foreground: "hsl(...)" },
muted: { DEFAULT: "hsl(...)", foreground: "hsl(...)" },
destructive: { DEFAULT: "hsl(...)", foreground: "hsl(...)" },
background: "hsl(...)",
foreground: "hsl(...)",
border: "hsl(...)",
},
typography: {
sans: ["Your Choice", "system-ui", "sans-serif"],
display: ["Your Display Font", "sans-serif"],
},
borderRadius: { sm: "...", DEFAULT: "...", lg: "..." },
};---
Step 3: Tailwind Version Decision Tree ⚠️ CRITICAL
┌─────────────────────────────────────────────────────────────────┐
│ FIRST: Check Tailwind version │
│ Command: grep '"tailwindcss"' package.json │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Version 3.x? ──────────────────────────────────────────────────┐
│ │ │
│ │ Configuration location: tailwind.config.js │
│ │ Dark mode: darkMode: "class" │
│ │ CSS variable format: --primary: 262 83% 58% │
│ │ Color reference: hsl(var(--primary)) │
│ │ │
│ └──────────────────────────────────────────────────────────────┘
│ │
│ Version 4.x? ──────────────────────────────────────────────────┐
│ │ │
│ │ Configuration location: CSS @theme inline │
│ │ Dark mode: @variant dark (&:where(.dark, .dark *)) │
│ │ CSS variable format: --primary-color: hsl(262 83% 58%) │
│ │ Color reference: var(--primary-color) │
│ │ Color naming: MUST use --color-* prefix in @theme │
│ │ │
│ │ ⚠️ tailwind.config.js colors will be IGNORED in v4! │
│ │ │
│ └──────────────────────────────────────────────────────────────┘
└─────────────────────────────────────────────────────────────────┘Tailwind v4 CSS Template
@import "tailwindcss";
@theme inline {
--radius-lg: 0.75rem;
--radius-md: calc(0.75rem - 2px);
--radius-sm: calc(0.75rem - 4px);
--color-background: var(--background-color);
--color-foreground: var(--foreground-color);
--color-primary: var(--primary-color);
--color-primary-foreground: var(--primary-foreground-color);
--color-secondary: var(--secondary-color);
--color-secondary-foreground: var(--secondary-foreground-color);
--color-muted: var(--muted-color);
--color-muted-foreground: var(--muted-foreground-color);
--color-accent: var(--accent-color);
--color-accent-foreground: var(--accent-foreground-color);
--color-destructive: var(--destructive-color);
--color-destructive-foreground: var(--destructive-foreground-color);
--color-card: var(--card-color);
--color-card-foreground: var(--card-foreground-color);
--color-popover: var(--popover-color);
--color-popover-foreground: var(--popover-foreground-color);
--color-border: var(--border-color);
--color-input: var(--input-color);
--color-ring: var(--ring-color);
}
@variant dark (&:where(.dark, .dark *));
@layer base {
:root {
/* Light mode - USE FULL hsl() VALUES */
--background-color: hsl(H S% L%);
--foreground-color: hsl(H S% L%);
--primary-color: hsl(H S% L%);
--primary-foreground-color: hsl(H S% L%);
/* ... complete all semantic colors ... */
}
.dark {
/* Dark mode variants */
--background-color: hsl(H S% L%);
--foreground-color: hsl(H S% L%);
/* ... complete all semantic colors ... */
}
}---
Step 4-6: Project Setup
Standard Shadcn UI setup. Configure components.json, create project structure.
---
🔧 Retrofit Workflow (Steps 7-11)
For existing projects, execute this complete flow systematically.
Step 7: Audit Hardcoded Colors
Execute these grep commands BEFORE making any changes:
# Primary audit
grep -rn "bg-gray-" src/
grep -rn "text-gray-" src/
grep -rn "border-gray-" src/
grep -rn "bg-white" src/
grep -rn "bg-black" src/
# Secondary audit
grep -rn "bg-blue-\|text-blue-" src/
grep -rn "bg-red-\|text-red-" src/
grep -rn "bg-green-\|text-green-" src/Step 7.5: 📱 Mobile First Detection & Decision
Execute detection commands:
# Check for Mobile First indicators
grep -rn "sm:" src/ | wc -l
grep -rn "md:" src/ | wc -l
grep -rn "lg:" src/ | wc -l
# Check for Desktop First indicators (max-width = desktop first)
grep -rn "@media.*max-width" src/ | head -5
# Sample responsive patterns
grep -rn "flex.*sm:\|flex.*md:" src/ | head -10Analyze the results:
| Indicator | Mobile First | Desktop First |
|---|---|---|
| Base styles | Mobile layout (stack, full-width) | Desktop layout (row, fixed-width) |
| Breakpoint usage | sm:, md:, lg: for enhancements | max-width media queries |
| CSS pattern | Progressive enhancement | Graceful degradation |
Decision flow:
Mobile First detected?
├─ YES → Continue with Mobile First strategy
│ Use mobile-base + sm:/md:/lg: enhancements
│
└─ NO → ASK USER:
"检测到项目未采用 Mobile First 策略。
是否需要改造为 Mobile First 响应式设计?
优点:
✓ 更好的移动端性能(加载更少的覆盖样式)
✓ 优先保证移动用户体验
✓ 符合现代响应式设计标准
缺点:
✗ 需要重构现有断点逻辑
✗ 可能影响现有桌面布局"
User: YES → Execute Mobile First Retrofit (see below)
User: NO → Skip Mobile First, continue with theme retrofit onlyMobile First Retrofit (if user confirms)
Common transformations:
| Desktop First Pattern | Mobile First Pattern |
|---|---|
hidden md:block | block md:hidden → hidden md:block (verify intent) |
flex-row (base) | flex-col (base) + md:flex-row |
w-1/3 (base) | w-full (base) + md:w-1/3 |
text-lg (base) | text-base (base) + md:text-lg |
p-8 (base) | p-4 (base) + md:p-8 |
grid-cols-3 (base) | grid-cols-1 (base) + md:grid-cols-2 lg:grid-cols-3 |
Priority components to retrofit:
1. Layout components (Header, Sidebar, Footer) 2. Navigation components (Navbar, MobileMenu) 3. Grid/List views (CardGrid, PhotoGrid) 4. Forms and inputs (touch-friendly sizing)
Step 8: Ensure Theme Toggle
Check for these components. If missing, create them:
1. src/hooks/useTheme.ts - Theme state management 2. src/components/ui/theme-toggle.tsx - UI toggle component 3. Theme initialization in main.tsx (prevent flash)
Step 9: Color Replacement Map
| Hardcoded | Replace With |
|---|---|
bg-white | bg-background or bg-card |
bg-gray-50/100 | bg-muted |
text-gray-900/700 | text-foreground |
text-gray-600/500/400 | text-muted-foreground |
border-gray-200/300 | border-border |
bg-blue-* | bg-primary |
text-blue-* | text-primary |
bg-red-* | bg-destructive |
bg-green-* | bg-success |
hover:bg-gray-* | hover:bg-accent |
Step 10: Overlay Components ⚠️ CRITICAL
Mobile overlay components (Sidebar, Modal, Dropdown, Drawer) MUST use explicit colors, NOT CSS variables!
// ❌ WRONG - CSS variables may fail on mobile overlays
<aside className="bg-card text-foreground">
// ✅ CORRECT - Explicit colors with dark: prefix
<aside className="bg-white dark:bg-slate-900 text-gray-900 dark:text-gray-100">| CSS Variable | Light Explicit | Dark Explicit |
|---|---|---|
bg-card | bg-white | dark:bg-slate-900 |
text-foreground | text-gray-900 | dark:text-gray-100 |
border-border | border-gray-200 | dark:border-slate-700 |
text-muted-foreground | text-gray-500 | dark:text-gray-400 |
Step 11: Gradient Text Dark Mode
`bg-clip-text text-transparent` may be invisible in dark mode!
// ❌ DANGEROUS
<h1 className="bg-linear-to-r from-primary to-accent bg-clip-text text-transparent">
// ✅ SAFE
<h1 className="text-foreground font-bold">---
🔍 Self-Verification Checkpoints
After Configuration Changes
# Verify Tailwind v4 setup
grep -n "@theme inline" src/index.css
grep -n "@variant dark" src/index.css
grep -n "\-\-.*\-color:" src/index.css | head -5After Color Replacements
# Should return minimal results (only overlay components)
grep -rn "bg-gray-\|text-gray-" src/ | grep -v "dark:" | wc -l📱 Mobile First Verification
# Check Mobile First adoption ratio
echo "Mobile First indicators (sm:/md:/lg: prefixes):"
grep -rn "sm:\|md:\|lg:" src/ | wc -l
echo "Desktop First indicators (max-width):"
grep -rn "max-width\|max-md:\|max-lg:" src/ | wc -l
# Verify base styles are mobile-friendly
grep -rn "flex-col" src/ | wc -l # Should be high
grep -rn "w-full" src/ | wc -l # Should be high
grep -rn "grid-cols-1" src/ | wc -l # Should be presentBrowser Console Verification
// Run in DevTools - should NOT return empty strings
const root = document.documentElement;
console.log('foreground:', getComputedStyle(root).getPropertyValue('--foreground-color'));
console.log('background:', getComputedStyle(root).getPropertyValue('--background-color'));
console.log('primary:', getComputedStyle(root).getPropertyValue('--primary-color'));📱 Mobile First Browser Verification
// Resize to mobile viewport (375px) and verify:
// 1. No horizontal scrolling
// 2. Touch targets are at least 44x44px
// 3. Text is readable without zooming
// 4. Navigation is accessible---
🚨 Troubleshooting Decision Tree
┌─────────────────────────────────────────────────────────────────┐
│ SYMPTOM: Colors not working │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Text nearly invisible / same as background? │
│ │ │
│ ├─ Check: Is this Tailwind v4? │
│ │ └─ YES → Ensure @theme inline is configured │
│ │ └─ NO → Check tailwind.config.js colors │
│ │ │
│ dark: prefix not working? │
│ │ │
│ └─ Add: @variant dark (&:where(.dark, .dark *)); │
│ │
│ Colors visible only when text selected? │
│ │ │
│ └─ CSS variables returning empty string │
│ └─ Fix: Ensure :root defines --*-color variables │
│ │
└─────────────────────────────────────────────────────────────────┘---
🎯 High-Priority Components Checklist
When retrofitting, always check these components (common sources of issues):
| Layer | Component | Common Issue |
|---|---|---|
| UI | dropdown-menu.tsx | bg-white → bg-popover |
| UI | dialog.tsx | bg-white → bg-card |
| Layout | sidebar/index.tsx | All hardcoded colors |
| Layout | Header/index.tsx | Background, border, text |
| Pages | *Page.tsx files | Page-level backgrounds |
| Business | Loading/Skeleton | Animation colors |
---
🎨 Typography Quick Reference
| Mood | Display Font | Body Font |
|---|---|---|
| Modern Tech | Clash Display | Plus Jakarta Sans |
| Clean Minimal | Geist | Geist |
| Editorial | Playfair Display | Source Serif Pro |
| Playful | Fredoka | Nunito |
| Luxury | Cormorant Garamond | Lora |
| Brutalist | Archivo Black | IBM Plex Mono |
AVOID: Inter, Roboto, Arial, Space Grotesk (overused)
---
📱 Mobile First Quick Reference
Breakpoint Strategy
| Breakpoint | Viewport | Usage |
|---|---|---|
| (base) | < 640px | Mobile phones - START HERE |
sm: | ≥ 640px | Large phones / small tablets |
md: | ≥ 768px | Tablets |
lg: | ≥ 1024px | Laptops / small desktops |
xl: | ≥ 1280px | Desktops |
2xl: | ≥ 1536px | Large monitors |
Common Mobile First Patterns
// Layout: Stack on mobile, row on desktop
<div className="flex flex-col gap-4 md:flex-row md:gap-6">
// Grid: 1 column mobile → 2 tablet → 3 desktop
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
// Spacing: Tighter on mobile, spacious on desktop
<section className="px-4 py-6 md:px-8 md:py-12 lg:px-16">
// Typography: Smaller on mobile
<h1 className="text-2xl font-bold md:text-4xl lg:text-5xl">
// Hide/Show: Mobile menu vs desktop nav
<nav className="hidden md:flex"> // Desktop nav
<button className="md:hidden"> // Mobile menu button
// Touch-friendly buttons (min 44x44px touch target)
<button className="min-h-[44px] min-w-[44px] px-4 py-3 md:py-2">Mobile First Anti-Patterns
// ❌ Desktop First - Don't do this
<div className="flex-row max-md:flex-col">
<div className="w-1/3 max-md:w-full">
<div className="text-lg max-md:text-sm">
// ❌ Forgetting mobile base
<div className="md:flex"> // Hidden on mobile!
// ✅ Fix:
<div className="flex flex-col md:flex-row">---
📋 Retrofit Completion Checklist
□ Tailwind version confirmed and correct config approach used
□ CSS variables defined for :root and .dark
□ [v4] @theme inline configured with --color-* variables
□ [v4] @variant dark defined
□ useTheme hook exists and works
□ ThemeToggle component integrated
□ All bg-gray-* scanned and replaced
□ All text-gray-* scanned and replaced
□ All border-gray-* scanned and replaced
□ All bg-white scanned and replaced
□ Overlay components use explicit colors
□ Gradient text verified in dark mode
□ Browser verification passed
📱 Mobile First Checklist:
□ Mobile First detection executed
□ User decision recorded (if not Mobile First)
□ Base styles are mobile-friendly (flex-col, w-full, etc.)
□ Breakpoints enhance for larger screens (sm: → md: → lg:)
□ Touch targets are 44x44px minimum on mobile
□ Mobile navigation tested---
💡 For Claude Opus 4.5
Your creative capabilities are extraordinary. When implementing designs:
1. Think deeply about the aesthetic direction before writing code 2. Commit boldly to a distinctive vision - don't default to safe choices 3. 📱 Mobile First always - design for the smallest screen first, then enhance 4. Verify systematically using the checkpoints provided 5. Use tools efficiently - grep for audit, search_replace for changes, browser for verification
Every design should be unique. Vary between light/dark themes, different fonts, different aesthetics. Never converge on the same choices across implementations.
Mobile First mindset: Remember that the majority of web traffic is mobile. Starting with mobile constraints forces you to prioritize content and interactions, resulting in cleaner, more focused designs that scale gracefully to larger screens.
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
@import "tailwindcss";
/*
* Design System Theme Configuration
* Generated from: [DESIGN_SOURCE]
*
* Replace the HSL values below with extracted design tokens
*/
:root {
/* ========================================
* COLOR TOKENS - Light Mode
* ======================================== */
/* Background & Foreground */
--background: 0 0% 100%;
--foreground: 222 47% 11%;
/* Card Surface */
--card: 0 0% 100%;
--card-foreground: 222 47% 11%;
/* Popover Surface */
--popover: 0 0% 100%;
--popover-foreground: 222 47% 11%;
/* Primary Brand Color */
--primary: 262 83% 58%;
--primary-foreground: 0 0% 100%;
/* Secondary Color */
--secondary: 220 14% 96%;
--secondary-foreground: 220 9% 46%;
/* Muted Elements */
--muted: 220 14% 96%;
--muted-foreground: 220 9% 46%;
/* Accent Color */
--accent: 340 82% 52%;
--accent-foreground: 0 0% 100%;
/* Destructive Actions */
--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 100%;
/* Borders & Inputs */
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 262 83% 58%;
/* ========================================
* RADIUS TOKEN
* ======================================== */
--radius: 0.5rem;
/* ========================================
* TYPOGRAPHY TOKENS
* ======================================== */
--font-sans: "Plus Jakarta Sans", system-ui, sans-serif;
--font-display: "Clash Display", system-ui, sans-serif;
--font-mono: "JetBrains Mono", monospace;
/* ========================================
* ANIMATION TOKENS
* ======================================== */
--duration-fast: 150ms;
--duration-normal: 200ms;
--duration-slow: 300ms;
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
/* ========================================
* CHART COLORS (Optional)
* ======================================== */
--chart-1: 262 83% 58%;
--chart-2: 340 82% 52%;
--chart-3: 142 76% 36%;
--chart-4: 38 92% 50%;
--chart-5: 221 83% 53%;
}
/* ==========================================
* DARK MODE OVERRIDES
* ========================================== */
.dark {
--background: 222 47% 11%;
--foreground: 0 0% 98%;
--card: 217 33% 17%;
--card-foreground: 0 0% 98%;
--popover: 217 33% 17%;
--popover-foreground: 0 0% 98%;
--primary: 262 83% 68%;
--primary-foreground: 222 47% 11%;
--secondary: 217 33% 17%;
--secondary-foreground: 0 0% 98%;
--muted: 217 33% 17%;
--muted-foreground: 215 20% 65%;
--accent: 340 82% 62%;
--accent-foreground: 0 0% 100%;
--destructive: 0 62% 50%;
--destructive-foreground: 0 0% 98%;
--border: 217 33% 22%;
--input: 217 33% 22%;
--ring: 262 83% 68%;
}
/* ==========================================
* BASE STYLES
* ========================================== */
* {
border-color: hsl(var(--border));
}
body {
background-color: hsl(var(--background));
color: hsl(var(--foreground));
font-family: var(--font-sans);
}
/* ==========================================
* CUSTOM UTILITIES
* ========================================== */
/* Text balance for headings */
.text-balance {
text-wrap: balance;
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Focus visible styles */
:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
}
/* Selection styling */
::selection {
background-color: hsl(var(--primary) / 0.2);
color: hsl(var(--primary));
}
/* ==========================================
* ANIMATION KEYFRAMES
* ========================================== */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scale-in {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* Utility classes for animations */
.animate-fade-in {
animation: fade-in var(--duration-normal) var(--ease-default);
}
.animate-slide-up {
animation: slide-up var(--duration-normal) var(--ease-default);
}
.animate-scale-in {
animation: scale-in var(--duration-normal) var(--ease-bounce);
}
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
/**
* Utility function to merge Tailwind CSS classes
* Combines clsx for conditional classes with tailwind-merge for deduplication
*
* @example
* cn("px-4 py-2", isActive && "bg-primary", className)
*/
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
/**
* Format a date for display
*/
export function formatDate(date: Date | string): string {
return new Intl.DateTimeFormat("en-US", {
month: "long",
day: "numeric",
year: "numeric",
}).format(new Date(date));
}
/**
* Delay execution for a specified duration
*/
export function delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Generate a unique ID
*/
export function generateId(): string {
return Math.random().toString(36).substring(2, 9);
}
/**
* Capitalize the first letter of a string
*/
export function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* Truncate text to a specified length
*/
export function truncate(str: string, length: number): string {
if (str.length <= length) return str;
return str.slice(0, length) + "...";
}
import type { Config } from "tailwindcss";
/**
* Tailwind CSS v4 Configuration
* Generated from: [DESIGN_SOURCE]
*
* Note: Most theming is done via CSS variables in globals.css
* This config extends the default theme with custom values
*/
export default {
darkMode: "class",
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
/* ========================================
* COLORS (CSS Variable References)
* ======================================== */
colors: {
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
chart: {
"1": "hsl(var(--chart-1))",
"2": "hsl(var(--chart-2))",
"3": "hsl(var(--chart-3))",
"4": "hsl(var(--chart-4))",
"5": "hsl(var(--chart-5))",
},
},
/* ========================================
* BORDER RADIUS
* ======================================== */
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
/* ========================================
* TYPOGRAPHY
* ======================================== */
fontFamily: {
sans: ["var(--font-sans)"],
display: ["var(--font-display)"],
mono: ["var(--font-mono)"],
},
/* ========================================
* ANIMATIONS
* ======================================== */
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
"fade-in": {
from: { opacity: "0" },
to: { opacity: "1" },
},
"fade-out": {
from: { opacity: "1" },
to: { opacity: "0" },
},
"slide-in-from-top": {
from: { transform: "translateY(-100%)" },
to: { transform: "translateY(0)" },
},
"slide-in-from-bottom": {
from: { transform: "translateY(100%)" },
to: { transform: "translateY(0)" },
},
"slide-in-from-left": {
from: { transform: "translateX(-100%)" },
to: { transform: "translateX(0)" },
},
"slide-in-from-right": {
from: { transform: "translateX(100%)" },
to: { transform: "translateX(0)" },
},
"scale-in": {
from: { transform: "scale(0.95)", opacity: "0" },
to: { transform: "scale(1)", opacity: "1" },
},
"spin-slow": {
from: { transform: "rotate(0deg)" },
to: { transform: "rotate(360deg)" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
"fade-in": "fade-in 0.2s ease-out",
"fade-out": "fade-out 0.2s ease-out",
"slide-in-from-top": "slide-in-from-top 0.3s ease-out",
"slide-in-from-bottom": "slide-in-from-bottom 0.3s ease-out",
"slide-in-from-left": "slide-in-from-left 0.3s ease-out",
"slide-in-from-right": "slide-in-from-right 0.3s ease-out",
"scale-in": "scale-in 0.2s ease-out",
"spin-slow": "spin-slow 3s linear infinite",
},
/* ========================================
* SPACING EXTENSIONS
* ======================================== */
spacing: {
"18": "4.5rem",
"22": "5.5rem",
"26": "6.5rem",
"30": "7.5rem",
},
},
},
plugins: [require("tailwindcss-animate")],
} satisfies Config;
Design Analysis Guide
Comprehensive guide for extracting design tokens from visual references.
Color Extraction Process
Step 1: Identify the Color Hierarchy
When analyzing a design screenshot, identify colors in this order:
1. Primary Color - The most prominent brand color
- Usually appears in CTAs, links, and key interactive elements
- Should have good contrast ratios
2. Secondary Color - Supporting brand color
- Often used for less prominent actions
- May be a desaturated version of primary
3. Accent Color - Highlight color
- Used sparingly for emphasis
- Often complementary or contrasting to primary
4. Neutral Palette - Grays and background colors
- Extract at least 5-7 shades from lightest to darkest
- Pay attention to warm vs cool undertones
5. Semantic Colors - Success, warning, error states
- If not visible, derive from primary color family
Step 2: Convert to HSL Format
Shadcn UI uses HSL format for maximum flexibility:
H (Hue): 0-360 degrees
S (Saturation): 0-100%
L (Lightness): 0-100%Benefits of HSL:
- Easy to create color variations (adjust L for tints/shades)
- Consistent saturation across palette
- Dark mode: invert L values while keeping H and S
Step 3: Create Color Scale
For each primary color, generate a scale:
--primary-50: H S 97%; /* Lightest */
--primary-100: H S 94%;
--primary-200: H S 86%;
--primary-300: H S 76%;
--primary-400: H S 66%;
--primary-500: H S 56%; /* Base */
--primary-600: H S 46%;
--primary-700: H S 36%;
--primary-800: H S 26%;
--primary-900: H S 16%; /* Darkest */Typography Analysis
Identifying Font Families
Look for clues in the design:
1. Headings - Often use display/decorative fonts
- Check for variable weight usage
- Note if condensed or extended variants are used
2. Body Text - Prioritize readability
- Usually 16-18px base size
- Line height 1.5-1.75 for body
3. UI Elements - Buttons, labels, captions
- May use different weight than body
- Often slightly smaller (14px)
Common Font Characteristics to Match
| Characteristic | Options |
|---|---|
| x-height | Low (traditional) / High (modern) |
| Stroke contrast | Low (geometric) / High (humanist) |
| Letter spacing | Tight / Normal / Loose |
| Weight range | Limited (2-3) / Variable (many) |
Font Pairing Suggestions
Rule of Thumb: Pair contrasting fonts (serif + sans) or related fonts (same family/foundry)
| Design Mood | Heading | Body |
|---|---|---|
| Tech Startup | Clash Display | Plus Jakarta Sans |
| SaaS Product | Geist | Geist Mono |
| Editorial | Playfair Display | Source Serif Pro |
| E-commerce | DM Serif Display | DM Sans |
| Finance | Libre Franklin | Libre Franklin |
Spacing System Analysis
Identifying Base Unit
Most designs use a base unit (commonly 4px or 8px):
4px base: 4, 8, 12, 16, 20, 24, 32, 48, 64...
8px base: 8, 16, 24, 32, 48, 64, 96, 128...Component Spacing Patterns
Analyze these elements:
- Button padding: vertical / horizontal ratio (usually 1:2 or 1:3)
- Card padding: internal spacing
- Section margins: vertical spacing between sections
- Gap values: space between flex/grid items
Border Radius Analysis
Style Categories
| Pattern | Values | Design Mood |
|---|---|---|
| Sharp | 0-2px | Technical, precise |
| Subtle | 4-8px | Clean, professional |
| Rounded | 12-16px | Friendly, approachable |
| Pill | 9999px | Playful, modern |
| Mixed | Varies by component | Dynamic, interesting |
Component-Specific Radius
/* Small elements (badges, tags) */
--radius-sm: 4px;
/* Medium elements (inputs, buttons) */
--radius-md: 8px;
/* Large elements (cards, dialogs) */
--radius-lg: 12px;
/* Full round (avatars, pills) */
--radius-full: 9999px;Shadow Analysis
Depth Levels
/* Elevation 1: Subtle lift */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
/* Elevation 2: Cards, dropdowns */
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
/* Elevation 3: Modals, popovers */
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
/* Elevation 4: Floating elements */
--shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);Modern Shadow Trends
1. Soft Shadows - Multiple layers, low opacity 2. Colored Shadows - Tinted with primary color 3. Hard Shadows - Offset, no blur (neo-brutalism)
Animation Characteristics
Timing Functions
| Feel | Easing | CSS Value |
|---|---|---|
| Snappy | Ease-out | cubic-bezier(0, 0, 0.2, 1) |
| Smooth | Ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) |
| Bouncy | Spring | cubic-bezier(0.34, 1.56, 0.64, 1) |
| Gentle | Ease | cubic-bezier(0.25, 0.1, 0.25, 1) |
Duration Guidelines
/* Micro-interactions */
--duration-fast: 150ms;
/* Standard transitions */
--duration-normal: 200ms;
/* Complex animations */
--duration-slow: 300ms;
/* Page transitions */
--duration-slower: 500ms;Dark Mode Considerations
Color Transformation Rules
1. Background: Invert but not to pure black (use gray-900) 2. Text: Reduce contrast slightly (gray-100 instead of white) 3. Borders: Often more visible in dark mode 4. Shadows: May need to be more pronounced or colored 5. Primary Colors: May need higher luminance for accessibility
Dark Mode Pattern
:root {
--background: 0 0% 100%; /* White */
--foreground: 222 47% 11%; /* Near black */
}
.dark {
--background: 222 47% 11%; /* Near black */
--foreground: 0 0% 98%; /* Off white */
}Checklist Summary
Before generating configuration:
- [ ] Primary color identified and converted to HSL
- [ ] Full neutral palette extracted (5+ shades)
- [ ] Font families identified for heading/body
- [ ] Base spacing unit determined
- [ ] Border radius pattern categorized
- [ ] Shadow style identified
- [ ] Animation feel characterized
- [ ] Dark mode colors derived
Shadcn UI Customization Guide
Advanced theming and customization for Shadcn UI components.
Understanding Shadcn Architecture
Shadcn UI is not a component library - it's a collection of re-usable components that you copy into your project. This means:
1. Full ownership - Components live in your codebase 2. Complete customization - Modify anything directly 3. No version conflicts - No external dependencies to manage 4. Design system flexibility - Adapt to any design system
Theme Configuration
components.json Structure
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}Style Options
| Style | Description |
|---|---|
new-york | Smaller, refined components with shadows |
default | Larger, flatter components |
CSS Variables Setup
Complete Theme Variables
:root {
/* Background colors */
--background: 0 0% 100%;
--foreground: 222 47% 11%;
/* Card surface */
--card: 0 0% 100%;
--card-foreground: 222 47% 11%;
/* Popover surface */
--popover: 0 0% 100%;
--popover-foreground: 222 47% 11%;
/* Primary action color */
--primary: 262 83% 58%;
--primary-foreground: 0 0% 100%;
/* Secondary action color */
--secondary: 220 14% 96%;
--secondary-foreground: 220 9% 46%;
/* Muted elements */
--muted: 220 14% 96%;
--muted-foreground: 220 9% 46%;
/* Accent elements */
--accent: 220 14% 96%;
--accent-foreground: 222 47% 11%;
/* Destructive actions */
--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 100%;
/* Borders and inputs */
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 262 83% 58%;
/* Border radius */
--radius: 0.5rem;
/* Chart colors (optional) */
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
--background: 222 47% 11%;
--foreground: 0 0% 98%;
--card: 222 47% 11%;
--card-foreground: 0 0% 98%;
--popover: 222 47% 11%;
--popover-foreground: 0 0% 98%;
--primary: 262 83% 68%;
--primary-foreground: 222 47% 11%;
--secondary: 217 33% 17%;
--secondary-foreground: 0 0% 98%;
--muted: 217 33% 17%;
--muted-foreground: 215 20% 65%;
--accent: 217 33% 17%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62% 30%;
--destructive-foreground: 0 0% 98%;
--border: 217 33% 17%;
--input: 217 33% 17%;
--ring: 262 83% 58%;
}Component Customization Examples
Button Variants
// components/ui/button.tsx
import { cva, type VariantProps } from "class-variance-authority";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
// Custom variants
gradient:
"bg-linear-to-r from-primary to-accent text-white shadow-lg hover:opacity-90",
glow:
"bg-primary text-primary-foreground shadow-[0_0_20px_hsl(var(--primary)/0.5)] hover:shadow-[0_0_30px_hsl(var(--primary)/0.7)]",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
xl: "h-12 rounded-lg px-10 text-base",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);Card Enhancements
// Enhanced card with hover effects
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-xl border bg-card text-card-foreground shadow",
// Hover effects
"transition-all duration-200",
"hover:shadow-lg hover:-translate-y-0.5",
// Border glow on hover
"hover:border-primary/20",
className
)}
{...props}
/>
));Input with Focus Effects
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm",
// Transitions
"transition-all duration-200",
// Focus states
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
"focus-visible:border-primary",
// Custom focus glow
"focus-visible:shadow-[0_0_0_3px_hsl(var(--primary)/0.1)]",
// Placeholder styling
"placeholder:text-muted-foreground",
// Disabled state
"disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
}
);Adding Custom Components
Glassmorphism Card
// components/ui/glass-card.tsx
import { cn } from "@/lib/utils";
interface GlassCardProps extends React.HTMLAttributes<HTMLDivElement> {}
export function GlassCard({ className, ...props }: GlassCardProps) {
return (
<div
className={cn(
"rounded-xl",
"bg-white/10 dark:bg-white/5",
"backdrop-blur-lg",
"border border-white/20",
"shadow-xl",
className
)}
{...props}
/>
);
}Gradient Border
// components/ui/gradient-border.tsx
export function GradientBorder({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<div className="relative p-[1px] rounded-lg bg-linear-to-r from-primary via-accent to-primary">
<div
className={cn(
"bg-background rounded-lg",
className
)}
>
{children}
</div>
</div>
);
}Animation Patterns
Micro-interactions
// Hover scale effect
<button className="transition-transform hover:scale-105 active:scale-95">
Click me
</button>
// Fade in on mount
<div className="animate-in fade-in duration-500">
Content
</div>
// Slide up on mount
<div className="animate-in slide-in-from-bottom-4 duration-500">
Content
</div>
// Staggered animation
{items.map((item, index) => (
<div
key={item.id}
className="animate-in fade-in slide-in-from-bottom-4"
style={{ animationDelay: `${index * 100}ms` }}
>
{item.content}
</div>
))}Loading States
// Skeleton with shimmer
<div className="animate-pulse bg-muted rounded-md h-4 w-full" />
// Spinner
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />Color Scheme Presets
Tech/SaaS
:root {
--primary: 221 83% 53%; /* Blue */
--accent: 262 83% 58%; /* Purple */
--background: 0 0% 100%;
}E-commerce
:root {
--primary: 142 76% 36%; /* Green */
--accent: 38 92% 50%; /* Orange */
--background: 0 0% 100%;
}Creative/Portfolio
:root {
--primary: 340 82% 52%; /* Pink */
--accent: 262 83% 58%; /* Purple */
--background: 240 10% 4%; /* Near black */
}Finance
:root {
--primary: 215 16% 47%; /* Steel gray */
--accent: 142 76% 36%; /* Green */
--background: 0 0% 100%;
}Best Practices
1. Consistent Spacing
Use Tailwind's spacing scale consistently:
gap-2for tight groupingsgap-4for related elementsgap-6orgap-8for sections
2. Typography Hierarchy
<h1 className="text-4xl font-bold tracking-tight">Main Title</h1>
<h2 className="text-2xl font-semibold">Section Title</h2>
<h3 className="text-xl font-medium">Subsection</h3>
<p className="text-base text-muted-foreground">Body text</p>
<span className="text-sm text-muted-foreground">Caption</span>3. Interactive States
Always include:
:hover- Visual feedback:focus-visible- Keyboard navigation:active- Press feedback:disabled- Unavailable state
4. Dark Mode Considerations
- Test all color combinations in both modes
- Ensure sufficient contrast (WCAG AA minimum)
- Adjust shadows (often need to be more subtle in dark mode)
- Consider using ring instead of shadow for focus states
Tailwind CSS v4 Syntax Reference
Essential syntax changes for Tailwind CSS v4 compatibility.
Gradient Syntax
Old v3 Syntax (Deprecated)
<!-- ❌ Don't use -->
<div class="bg-gradient-to-r from-purple-500 to-pink-500"></div>New v4 Syntax (Required)
<!-- ✅ Use this -->
<div class="bg-linear-to-r from-purple-500 to-pink-500"></div>Full Gradient Mapping
| v3 (Deprecated) | v4 (Use This) |
|---|---|
bg-gradient-to-t | bg-linear-to-t |
bg-gradient-to-tr | bg-linear-to-tr |
bg-gradient-to-r | bg-linear-to-r |
bg-gradient-to-br | bg-linear-to-br |
bg-gradient-to-b | bg-linear-to-b |
bg-gradient-to-bl | bg-linear-to-bl |
bg-gradient-to-l | bg-linear-to-l |
bg-gradient-to-tl | bg-linear-to-tl |
Additional Gradient Types in v4
<!-- Radial gradients -->
<div class="bg-radial from-purple-500 to-pink-500"></div>
<!-- Conic gradients -->
<div class="bg-conic from-purple-500 via-pink-500 to-orange-500"></div>Opacity Syntax
Old v3 Syntax (Deprecated)
<!-- ❌ Don't use -->
<div class="bg-black bg-opacity-50"></div>
<div class="text-white text-opacity-75"></div>
<div class="border-gray-500 border-opacity-50"></div>New v4 Syntax (Required)
<!-- ✅ Use this -->
<div class="bg-black/50"></div>
<div class="text-white/75"></div>
<div class="border-gray-500/50"></div>Full Opacity Mapping
| v3 (Deprecated) | v4 (Use This) |
|---|---|
bg-opacity-* | bg-color/opacity |
text-opacity-* | text-color/opacity |
border-opacity-* | border-color/opacity |
ring-opacity-* | ring-color/opacity |
divide-opacity-* | divide-color/opacity |
placeholder-opacity-* | placeholder:text-color/opacity |
Common Opacity Values
<!-- Background opacities -->
<div class="bg-white/0"></div> <!-- 0% -->
<div class="bg-white/5"></div> <!-- 5% -->
<div class="bg-white/10"></div> <!-- 10% -->
<div class="bg-white/20"></div> <!-- 20% -->
<div class="bg-white/25"></div> <!-- 25% -->
<div class="bg-white/30"></div> <!-- 30% -->
<div class="bg-white/40"></div> <!-- 40% -->
<div class="bg-white/50"></div> <!-- 50% -->
<div class="bg-white/60"></div> <!-- 60% -->
<div class="bg-white/70"></div> <!-- 70% -->
<div class="bg-white/75"></div> <!-- 75% -->
<div class="bg-white/80"></div> <!-- 80% -->
<div class="bg-white/90"></div> <!-- 90% -->
<div class="bg-white/95"></div> <!-- 95% -->
<div class="bg-white/100"></div> <!-- 100% -->
<!-- Arbitrary values -->
<div class="bg-white/[0.33]"></div> <!-- 33% -->CSS Import Syntax
Old v3 Syntax
@tailwind base;
@tailwind components;
@tailwind utilities;New v4 Syntax
@import "tailwindcss";Or with layers:
@import "tailwindcss/theme" layer(theme);
@import "tailwindcss/preflight" layer(base);
@import "tailwindcss/utilities" layer(utilities);Configuration Changes
Config File (v4 uses CSS-first approach)
/* globals.css */
@import "tailwindcss";
@theme {
--color-primary: oklch(65% 0.25 260);
--color-secondary: oklch(70% 0.15 200);
--font-sans: "Plus Jakarta Sans", system-ui, sans-serif;
--font-display: "Clash Display", system-ui, sans-serif;
--radius-lg: 0.75rem;
--radius-md: 0.5rem;
--radius-sm: 0.25rem;
}Optional tailwind.config.js
Still supported for complex configurations:
export default {
content: ["./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
// Custom extensions
},
},
plugins: [],
};Color Syntax
OKLCH Colors (Recommended in v4)
@theme {
/* OKLCH provides better perceptual uniformity */
--color-primary: oklch(65% 0.25 260);
/* Still works: HSL */
--color-secondary: hsl(220 80% 60%);
/* Still works: Hex */
--color-accent: #ff6b6b;
}HSL in CSS Variables (Shadcn Pattern)
:root {
/* Store without hsl() wrapper for flexibility */
--primary: 262 83% 58%;
--primary-foreground: 0 0% 100%;
}
/* Use with hsl() in Tailwind config */
.example {
background: hsl(var(--primary));
}Container Queries (New in v4)
<!-- Define container -->
<div class="@container">
<!-- Use container-based breakpoints -->
<div class="@sm:flex @md:grid @lg:hidden">
Content adapts to container, not viewport
</div>
</div>Logical Properties
<!-- Inline (horizontal in LTR) -->
<div class="ps-4 pe-4">Padding start/end</div>
<div class="ms-4 me-4">Margin start/end</div>
<!-- Block (vertical) -->
<div class="pbs-4 pbe-4">Padding block start/end</div>Modern Pseudo-Selectors
<!-- has() selector -->
<div class="has-[input:focus]:ring-2">
<input />
</div>
<!-- :not() selector -->
<div class="not-first:mt-4">
Margin top except first
</div>Variable Fonts
@theme {
--font-display: "Inter Variable", sans-serif;
}<!-- Font weight with variable fonts -->
<h1 class="font-display font-[450]">Variable weight</h1>Migration Checklist
When generating new code:
- [ ] Use
bg-linear-to-*instead ofbg-gradient-to-* - [ ] Use
color/opacityinstead of*-opacity-*classes - [ ] Use
@import "tailwindcss"in CSS - [ ] Consider OKLCH for color definitions
- [ ] Use CSS-first
@themewhen possible - [ ] Leverage new features: container queries, has(), etc.