skills/dieshen/shadcn-aesthetic/SKILL.md
Modern CSS/SCSS architecture based on shadcn/ui design principles. Use this when generating any CSS, SCSS, or styling code to ensure modern, refined, and accessible design patterns.
npx skillsauth add aiskillstore/marketplace shadcn-aestheticInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides comprehensive guidance for writing modern, refined CSS/SCSS that matches the shadcn/ui aesthetic - clean, minimal, accessible, and beautifully crafted.
Apply these patterns when:
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%;
}
// 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);
}
}
// 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);
}
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
}
.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
}
// Random pixel values
.button {
padding: 10px 22px;
margin: 13px;
}
// Inconsistent spacing
.card {
padding: 15px;
margin-bottom: 18px;
}
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);
}
.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);
}
}
// 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;
}
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;
}
.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));
}
// Random font sizes
h1 { font-size: 28px; }
h2 { font-size: 22px; }
p { font-size: 15px; }
// Hard-coded weights
.title { font-weight: 600; }
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;
}
.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);
}
// Slow, dated transitions
.button {
transition: all 0.3s ease;
}
// Transitioning too many properties
.card {
transition: all 0.5s;
}
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);
}
}
// Removing outline without replacement
button {
outline: none;
}
// Ugly focus states
input:focus {
border: 2px solid blue;
}
// 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;
}
// 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;
}
// Using margins instead of gap
.buttons button {
margin-right: 8px;
&:last-child {
margin-right: 0;
}
}
// Floats
.columns {
float: left;
width: 50%;
}
.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 {
// 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 {
// 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 {
// 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));
}
}
// 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));
}
// Media query approach (harder to control)
.card {
background: white;
color: black;
@media (prefers-color-scheme: dark) {
background: black;
color: white;
}
}
: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
}
: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);
}
// Show focus states only for keyboard navigation
.button {
&:focus {
outline: none;
}
&:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
}
}
.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;
}
@media (prefers-contrast: high) {
.button {
border-width: 2px;
}
.input {
border-width: 2px;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
// 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
}
}
Before finalizing any CSS, verify:
When in doubt, reference these patterns:
Remember: Subtle beats flashy. Consistent beats clever. Accessible beats everything.
development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.