Marketplace shadcn-aesthetic
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/dieshen/shadcn-aesthetic" ~/.claude/skills/aiskillstore-marketplace-shadcn-aesthetic && rm -rf "$T"
manifest:
skills/dieshen/shadcn-aesthetic/SKILL.mdsource content
Modern CSS Architecture (shadcn Aesthetic)
This skill provides comprehensive guidance for writing modern, refined CSS/SCSS that matches the shadcn/ui aesthetic - clean, minimal, accessible, and beautifully crafted.
When This Skill Activates
Apply these patterns when:
- Writing any CSS, SCSS, or styling code
- Creating component styles from scratch
- Refactoring existing styles
- Building design systems or theme systems
- Working on Blazor, React, Vue, or any web UI
Core Principles
- Use CSS variables for everything themeable
- HSL color system for easy manipulation
- Consistent spacing scale (4px base)
- Subtle, layered shadows
- Quick, smooth transitions (150ms)
- Proper focus states
- Modern layout primitives (Grid/Flex with gap)
- Dark mode first-class citizen
Color System
Variable Structure
Always use HSL-based CSS variables for colors:
:root { // Background colors --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; // Card colors --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; // Popover colors --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; // Primary brand colors --primary: 222.2 47.4% 11.2%; --primary-foreground: 210 40% 98%; // Secondary colors --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; // Muted colors --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; // Accent colors --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; // Destructive/error colors --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; // Border and input --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 222.2 84% 4.9%; // Border radius --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%; --primary: 210 40% 98%; --primary-foreground: 222.2 47.4% 11.2%; --secondary: 217.2 32.6% 17.5%; --secondary-foreground: 210 40% 98%; --muted: 217.2 32.6% 17.5%; --muted-foreground: 215 20.2% 65.1%; --accent: 217.2 32.6% 17.5%; --accent-foreground: 210 40% 98%; --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: 212.7 26.8% 83.9%; }
Usage
// Always use hsl() with var() .component { background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); // With opacity border: 1px solid hsl(var(--border) / 0.5); &:hover { background-color: hsl(var(--primary) / 0.9); } }
❌ Anti-Pattern (Don't Do This)
// Hard-coded hex colors .button { background: #007bff; color: #ffffff; } // RGB without variables .card { background: rgb(255, 255, 255); border: 1px solid rgba(0, 0, 0, 0.1); }
Spacing Scale
Use a consistent spacing scale based on 4px increments:
:root { --spacing-0: 0; --spacing-px: 1px; --spacing-0-5: 0.125rem; // 2px --spacing-1: 0.25rem; // 4px --spacing-1-5: 0.375rem; // 6px --spacing-2: 0.5rem; // 8px --spacing-2-5: 0.625rem; // 10px --spacing-3: 0.75rem; // 12px --spacing-3-5: 0.875rem; // 14px --spacing-4: 1rem; // 16px --spacing-5: 1.25rem; // 20px --spacing-6: 1.5rem; // 24px --spacing-7: 1.75rem; // 28px --spacing-8: 2rem; // 32px --spacing-9: 2.25rem; // 36px --spacing-10: 2.5rem; // 40px --spacing-11: 2.75rem; // 44px --spacing-12: 3rem; // 48px --spacing-14: 3.5rem; // 56px --spacing-16: 4rem; // 64px --spacing-20: 5rem; // 80px --spacing-24: 6rem; // 96px --spacing-32: 8rem; // 128px }
Usage
.button { padding: var(--spacing-2) var(--spacing-4); // 8px 16px gap: var(--spacing-2); // 8px } .card { padding: var(--spacing-6); // 24px margin-bottom: var(--spacing-4); // 16px }
❌ Anti-Pattern (Don't Do This)
// Random pixel values .button { padding: 10px 22px; margin: 13px; } // Inconsistent spacing .card { padding: 15px; margin-bottom: 18px; }
Shadow System
Use subtle, layered shadows for depth:
:root { // Subtle shadows --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-base: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); // Inner shadow --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); }
Usage
.card { box-shadow: var(--shadow-sm); &:hover { box-shadow: var(--shadow-md); } } .dropdown { box-shadow: var(--shadow-lg); } .input { box-shadow: var(--shadow-sm); &:focus { box-shadow: var(--shadow-sm), 0 0 0 2px hsl(var(--ring) / 0.2); } }
❌ Anti-Pattern (Don't Do This)
// Heavy, dated shadows .card { box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } // Single-layer shadows .button { box-shadow: 2px 2px 5px #999; }
Typography Scale
Use a harmonious type scale:
:root { // Font sizes --text-xs: 0.75rem; // 12px --text-sm: 0.875rem; // 14px --text-base: 1rem; // 16px --text-lg: 1.125rem; // 18px --text-xl: 1.25rem; // 20px --text-2xl: 1.5rem; // 24px --text-3xl: 1.875rem; // 30px --text-4xl: 2.25rem; // 36px --text-5xl: 3rem; // 48px // Line heights --leading-none: 1; --leading-tight: 1.25; --leading-snug: 1.375; --leading-normal: 1.5; --leading-relaxed: 1.625; --leading-loose: 2; // Font weights --font-thin: 100; --font-light: 300; --font-normal: 400; --font-medium: 500; --font-semibold: 600; --font-bold: 700; --font-extrabold: 800; // Font families --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace; }
Usage
.heading { font-size: var(--text-2xl); font-weight: var(--font-semibold); line-height: var(--leading-tight); letter-spacing: -0.025em; } .body-text { font-size: var(--text-base); line-height: var(--leading-relaxed); } .small-text { font-size: var(--text-sm); color: hsl(var(--muted-foreground)); }
❌ Anti-Pattern (Don't Do This)
// Random font sizes h1 { font-size: 28px; } h2 { font-size: 22px; } p { font-size: 15px; } // Hard-coded weights .title { font-weight: 600; }
Transitions & Animations
Use quick, smooth transitions:
:root { // Timing functions --ease-in: cubic-bezier(0.4, 0, 1, 1); --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); // Durations --duration-75: 75ms; --duration-100: 100ms; --duration-150: 150ms; --duration-200: 200ms; --duration-300: 300ms; --duration-500: 500ms; }
Usage
.button { transition: all var(--duration-150) var(--ease-in-out); &:hover { transform: translateY(-1px); } &:active { transform: translateY(0); } } // For specific properties .dropdown { transition-property: opacity, transform; transition-duration: var(--duration-150); transition-timing-function: var(--ease-out); }
❌ Anti-Pattern (Don't Do This)
// Slow, dated transitions .button { transition: all 0.3s ease; } // Transitioning too many properties .card { transition: all 0.5s; }
Focus States
Modern, accessible focus rings:
.button, .input, .link { // Remove default outline outline: none; // Add custom focus ring &:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; } } // For inputs with borders .input { &:focus-visible { outline: none; border-color: hsl(var(--ring)); box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2); } } // For cards and containers .card { &:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; border-radius: var(--radius); } }
❌ Anti-Pattern (Don't Do This)
// Removing outline without replacement button { outline: none; } // Ugly focus states input:focus { border: 2px solid blue; }
Modern Layout Patterns
Grid Layouts
// Auto-fit grid .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--spacing-6); } // Fixed columns with gap .two-column { display: grid; grid-template-columns: 1fr 2fr; gap: var(--spacing-8); } // Complex grid .dashboard-layout { display: grid; grid-template-columns: 250px 1fr; grid-template-rows: 60px 1fr; gap: var(--spacing-4); height: 100vh; }
Flex Layouts
// Modern flex with gap (not margin) .button-group { display: flex; align-items: center; gap: var(--spacing-2); } // Flex with proper wrapping .tag-list { display: flex; flex-wrap: wrap; gap: var(--spacing-2); } // Center content .centered { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
❌ Anti-Pattern (Don't Do This)
// Using margins instead of gap .buttons button { margin-right: 8px; &:last-child { margin-right: 0; } } // Floats .columns { float: left; width: 50%; }
Component Patterns
Button
.button { // Base styles display: inline-flex; align-items: center; justify-content: center; gap: var(--spacing-2); // Typography font-size: var(--text-sm); font-weight: var(--font-medium); line-height: var(--leading-none); // Spacing padding: var(--spacing-2) var(--spacing-4); // Visual border-radius: var(--radius); border: 1px solid transparent; background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); box-shadow: var(--shadow-sm); // Interaction cursor: pointer; transition: all var(--duration-150) var(--ease-in-out); user-select: none; // States &:hover { background-color: hsl(var(--primary) / 0.9); box-shadow: var(--shadow-md); } &:active { transform: translateY(1px); box-shadow: var(--shadow-sm); } &:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; } &:disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; } // Variants &--secondary { background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); &:hover { background-color: hsl(var(--secondary) / 0.8); } } &--outline { background-color: transparent; border-color: hsl(var(--input)); color: hsl(var(--foreground)); box-shadow: none; &:hover { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); } } &--ghost { background-color: transparent; box-shadow: none; &:hover { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); } } // Sizes &--sm { padding: var(--spacing-1-5) var(--spacing-3); font-size: var(--text-xs); } &--lg { padding: var(--spacing-3) var(--spacing-8); font-size: var(--text-base); } }
Input
.input { // Base styles display: flex; width: 100%; // Typography font-size: var(--text-sm); line-height: var(--leading-normal); // Spacing padding: var(--spacing-2) var(--spacing-3); // Visual border-radius: var(--radius); border: 1px solid hsl(var(--input)); background-color: hsl(var(--background)); color: hsl(var(--foreground)); box-shadow: var(--shadow-sm); // Interaction transition: all var(--duration-150) var(--ease-in-out); // Placeholder &::placeholder { color: hsl(var(--muted-foreground)); } // States &:hover { border-color: hsl(var(--input) / 0.8); } &:focus { outline: none; border-color: hsl(var(--ring)); box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2); } &:disabled { opacity: 0.5; cursor: not-allowed; background-color: hsl(var(--muted)); } // Error state &--error { border-color: hsl(var(--destructive)); &:focus { border-color: hsl(var(--destructive)); box-shadow: 0 0 0 2px hsl(var(--destructive) / 0.2); } } }
Card
.card { // Base styles display: flex; flex-direction: column; // Spacing padding: var(--spacing-6); gap: var(--spacing-4); // Visual border-radius: calc(var(--radius) + 2px); border: 1px solid hsl(var(--border)); background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); box-shadow: var(--shadow-sm); // Interaction transition: box-shadow var(--duration-150) var(--ease-in-out); &:hover { box-shadow: var(--shadow-md); } // Sub-components &__header { display: flex; flex-direction: column; gap: var(--spacing-1-5); } &__title { font-size: var(--text-2xl); font-weight: var(--font-semibold); line-height: var(--leading-tight); letter-spacing: -0.025em; } &__description { font-size: var(--text-sm); color: hsl(var(--muted-foreground)); } &__content { flex: 1; } &__footer { display: flex; align-items: center; gap: var(--spacing-2); padding-top: var(--spacing-4); border-top: 1px solid hsl(var(--border)); } }
Badge
.badge { // Base styles display: inline-flex; align-items: center; // Typography font-size: var(--text-xs); font-weight: var(--font-semibold); line-height: var(--leading-none); text-transform: uppercase; letter-spacing: 0.05em; // Spacing padding: var(--spacing-1) var(--spacing-2-5); // Visual border-radius: calc(var(--radius) - 2px); border: 1px solid transparent; background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); // Variants &--secondary { background-color: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); } &--outline { background-color: transparent; border-color: hsl(var(--border)); color: hsl(var(--foreground)); } &--destructive { background-color: hsl(var(--destructive)); color: hsl(var(--destructive-foreground)); } }
Dark Mode Strategy
CSS Variable Approach
// Define light mode in :root :root { --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; // ... all other variables } // Override for dark mode .dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; // ... all other variables } // Components automatically adapt .card { background-color: hsl(var(--background)); color: hsl(var(--foreground)); }
❌ Anti-Pattern (Don't Do This)
// Media query approach (harder to control) .card { background: white; color: black; @media (prefers-color-scheme: dark) { background: black; color: white; } }
Border Radius System
:root { --radius-none: 0; --radius-sm: 0.125rem; // 2px --radius-base: 0.25rem; // 4px --radius-md: 0.375rem; // 6px --radius-lg: 0.5rem; // 8px --radius-xl: 0.75rem; // 12px --radius-2xl: 1rem; // 16px --radius-3xl: 1.5rem; // 24px --radius-full: 9999px; // Default radius (customize per theme) --radius: var(--radius-lg); } // Usage .button { border-radius: var(--radius); } .card { border-radius: calc(var(--radius) + 2px); // Slightly larger } .avatar { border-radius: var(--radius-full); // Circle }
Z-Index System
:root { --z-0: 0; --z-10: 10; --z-20: 20; --z-30: 30; --z-40: 40; --z-50: 50; --z-dropdown: 1000; --z-sticky: 1100; --z-fixed: 1200; --z-modal-backdrop: 1300; --z-modal: 1400; --z-popover: 1500; --z-tooltip: 1600; --z-toast: 1700; } .dropdown { z-index: var(--z-dropdown); } .modal { z-index: var(--z-modal); }
Accessibility Patterns
Keyboard Navigation
// Show focus states only for keyboard navigation .button { &:focus { outline: none; } &:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; } }
Screen Reader Only
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }
High Contrast Support
@media (prefers-contrast: high) { .button { border-width: 2px; } .input { border-width: 2px; } }
Reduced Motion
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } }
Complete Example: Modern Component
// Alert Component .alert { // Layout display: flex; align-items: flex-start; gap: var(--spacing-3); // Spacing padding: var(--spacing-4); // Visual border-radius: var(--radius); border: 1px solid hsl(var(--border)); background-color: hsl(var(--background)); // Typography font-size: var(--text-sm); line-height: var(--leading-relaxed); // Icon &__icon { flex-shrink: 0; width: 1rem; height: 1rem; margin-top: 0.125rem; } // Content &__content { flex: 1; } &__title { font-weight: var(--font-medium); margin-bottom: var(--spacing-1); } &__description { color: hsl(var(--muted-foreground)); } // Variants &--info { border-color: hsl(210 100% 90%); background-color: hsl(210 100% 97%); .alert__icon { color: hsl(210 100% 45%); } } &--success { border-color: hsl(142 76% 85%); background-color: hsl(142 76% 96%); .alert__icon { color: hsl(142 76% 36%); } } &--warning { border-color: hsl(38 92% 85%); background-color: hsl(38 92% 95%); .alert__icon { color: hsl(38 92% 50%); } } &--error { border-color: hsl(0 84% 85%); background-color: hsl(0 84% 97%); .alert__icon { color: hsl(0 84% 60%); } } } // Dark mode .dark { .alert { &--info { border-color: hsl(210 100% 20%); background-color: hsl(210 100% 10%); .alert__icon { color: hsl(210 100% 70%); } } // ... other variants } }
Quality Checklist
Before finalizing any CSS, verify:
- Using CSS variables for colors
- HSL color format with opacity support
- Consistent spacing scale (4px base)
- Subtle, layered shadows
- Quick transitions (150ms default)
- Proper focus-visible states
- Modern layout (Grid/Flex with gap)
- Dark mode support
- Reduced motion support
- High contrast support
- Semantic class names (BEM or similar)
- No hard-coded colors
- No random pixel values
- Keyboard accessible
- Screen reader friendly
Reference Resources
When in doubt, reference these patterns:
- shadcn/ui components: https://ui.shadcn.com
- Radix UI primitives: https://www.radix-ui.com
- Tailwind CSS utilities: https://tailwindcss.com
Remember: Subtle beats flashy. Consistent beats clever. Accessible beats everything.