Join our Discord Community

Modern Minimal Shadcn Theme

Clean modern minimal theme with subtle purple accents for shadcn/ui. Swiss design principles with contemporary aesthetics. TypeScript ready.

Working with shadcn themes?

Join our Discord community for help from other shadcn developers working with themes and design systems.

Modern Minimal Shadcn Theme

After years of building interfaces that got cluttered with features and visual noise, started appreciating the power of restraint. This theme strips everything back to what actually matters—clean typography, subtle purple accents, and generous white space that lets content breathe.

Perfect for SaaS dashboards, professional portfolios, design agencies, or any React project where clarity and sophistication matter more than flashy design. The Source Serif 4 font adds just enough character without being distracting.

Installation

npx shadcn@latest add https://www.shadcn.io/registry/modern-minimal.json
npx shadcn@latest add https://www.shadcn.io/registry/modern-minimal.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/modern-minimal.json
bunx shadcn@latest add https://www.shadcn.io/registry/modern-minimal.json

Original theme by tweakcn.com

CSS Variables

Copy and paste the following CSS variables into your global CSS file:

:root {
  --background: oklch(1.00 0 0);
  --foreground: oklch(0.32 0 0);
  --card: oklch(1.00 0 0);
  --card-foreground: oklch(0.32 0 0);
  --popover: oklch(1.00 0 0);
  --popover-foreground: oklch(0.32 0 0);
  --primary: oklch(0.62 0.19 259.76);
  --primary-foreground: oklch(1.00 0 0);
  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.45 0.03 257.68);
  --muted: oklch(0.98 0 0);
  --muted-foreground: oklch(0.55 0.02 264.41);
  --accent: oklch(0.95 0.03 233.56);
  --accent-foreground: oklch(0.38 0.14 265.59);
  --destructive: oklch(0.64 0.21 25.39);
  --border: oklch(0.93 0.01 261.82);
  --input: oklch(0.93 0.01 261.82);
  --ring: oklch(0.62 0.19 259.76);
  --chart-1: oklch(0.62 0.19 259.76);
  --chart-2: oklch(0.55 0.22 262.96);
  --chart-3: oklch(0.49 0.22 264.43);
  --chart-4: oklch(0.42 0.18 265.55);
  --chart-5: oklch(0.38 0.14 265.59);
  --sidebar: oklch(0.98 0 0);
  --sidebar-foreground: oklch(0.14 0 0);
  --sidebar-primary: oklch(0.20 0 0);
  --sidebar-primary-foreground: oklch(0.98 0 0);
  --sidebar-accent: oklch(0.97 0 0);
  --sidebar-accent-foreground: oklch(0.20 0 0);
  --sidebar-border: oklch(0.92 0 0);
  --sidebar-ring: oklch(0.71 0 0);
  --destructive-foreground: oklch(1.0000 0 0);
  --font-serif: Source Serif 4, serif;
  --font-mono: JetBrains Mono, monospace;
  --radius: 0.375rem;
  --shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
  --shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
  --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
  --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
  --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
  --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
  --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
  --shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
  --tracking-normal: 0em;
}

.dark {
  --background: oklch(0.20 0 0);
  --foreground: oklch(0.92 0 0);
  --card: oklch(0.27 0 0);
  --card-foreground: oklch(0.92 0 0);
  --popover: oklch(0.27 0 0);
  --popover-foreground: oklch(0.92 0 0);
  --primary: oklch(0.62 0.19 259.76);
  --primary-foreground: oklch(1.00 0 0);
  --secondary: oklch(0.27 0 0);
  --secondary-foreground: oklch(0.92 0 0);
  --muted: oklch(0.27 0 0);
  --muted-foreground: oklch(0.72 0 0);
  --accent: oklch(0.38 0.14 265.59);
  --accent-foreground: oklch(0.88 0.06 254.63);
  --destructive: oklch(0.64 0.21 25.39);
  --border: oklch(0.37 0 0);
  --input: oklch(0.37 0 0);
  --ring: oklch(0.62 0.19 259.76);
  --chart-1: oklch(0.71 0.14 254.69);
  --chart-2: oklch(0.62 0.19 259.76);
  --chart-3: oklch(0.55 0.22 262.96);
  --chart-4: oklch(0.49 0.22 264.43);
  --chart-5: oklch(0.42 0.18 265.55);
  --sidebar: oklch(0.21 0.01 285.93);
  --sidebar-foreground: oklch(0.99 0 0);
  --sidebar-primary: oklch(0.49 0.24 264.40);
  --sidebar-primary-foreground: oklch(0.99 0 0);
  --sidebar-accent: oklch(0.27 0.01 286.10);
  --sidebar-accent-foreground: oklch(0.99 0 0);
  --sidebar-border: oklch(1.00 0 0 / 10%);
  --sidebar-ring: oklch(0.55 0.02 285.93);
  --destructive-foreground: oklch(1.0000 0 0);
  --font-serif: Source Serif 4, serif;
  --font-mono: JetBrains Mono, monospace;
  --radius: 0.375rem;
  --shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
  --shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
  --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
  --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
  --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
  --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
  --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
  --shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
}

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-chart-1: var(--chart-1);
  --color-chart-2: var(--chart-2);
  --color-chart-3: var(--chart-3);
  --color-chart-4: var(--chart-4);
  --color-chart-5: var(--chart-5);
  --color-sidebar: var(--sidebar);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-ring: var(--sidebar-ring);
  --color-destructive-foreground: var(--destructive-foreground);

  --font-sans: var(--font-sans);
  --font-mono: var(--font-mono);
  --font-serif: var(--font-serif);

  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  --shadow-2xs: var(--shadow-2xs);
  --shadow-xs: var(--shadow-xs);
  --shadow-sm: var(--shadow-sm);
  --shadow: var(--shadow);
  --shadow-md: var(--shadow-md);
  --shadow-lg: var(--shadow-lg);
  --shadow-xl: var(--shadow-xl);
  --shadow-2xl: var(--shadow-2xl);
}

Why this theme actually works

Minimalism isn't about removing everything—it's about removing everything that doesn't serve a purpose. That subtle purple provides just enough personality without overwhelming the content. The high contrast ratios and generous spacing create interfaces that users can actually focus on.

Most "minimal" themes end up being bland and personality-free. This one strikes the right balance by using restraint strategically. The purple appears only where it matters—primary actions, focus states, navigation highlights. Everything else gets out of the way.

Dark mode maintains the same principles but with carefully chosen grays that don't strain your eyes during long work sessions. The purple maintains its subtle presence while the overall aesthetic becomes more comfortable for extended use.

What's actually in this theme

Dead simple setup—copy the CSS variables into your globals.css and you're done. The Source Serif 4 font adds subtle sophistication without being pretentious, perfect for professional interfaces that need to feel approachable.

That refined purple is perfect for primary actions that should feel important but not aggressive—"Save," "Continue," "Submit." The clean grays and generous white space create calm, focused environments where users can actually think.

All contrast ratios pass WCAG AA standards because good minimalism never sacrifices usability for aesthetics. Since it uses standard shadcn color tokens, your TypeScript autocomplete for bg-primary, text-foreground, etc. works perfectly.

How to use this in projects

The purple should mark primary actions and important states—anything that deserves focused attention. Use it sparingly. The clean whites and light grays should dominate, creating that Swiss design philosophy where content is king.

This works especially well for productivity apps, professional dashboards, documentation sites, or any interface where users need to focus on tasks rather than fight with the design. Think Apple's design principles—powerful but invisible.

In practice, embrace the negative space. Don't feel pressured to fill every pixel. The generous spacing and restrained color palette work because they reduce cognitive load. Users spend less mental energy parsing the interface and more time on their actual work.

You might also like

FAQ