Join our Discord Community

Spotify Shadcn Theme

Spotify-inspired theme with signature green accents and sleek dark interface for shadcn/ui. Music platform aesthetic with modern design. TypeScript ready.

Working with shadcn themes?

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

Spotify Shadcn Theme

Been using Spotify for over a decade and always admired how they nail that perfect balance of dark sophistication with just enough color to keep things lively. This theme captures that exact same energy—sleek blacks and grays with that signature green that makes everything feel premium.

Perfect for music apps, content platforms, media dashboards, or any React project where you want that polished entertainment industry feel. The Lato font gives you that same clean, modern look that Spotify uses.

Installation

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

Original theme by tweakcn.com

CSS Variables

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

:root {
  --background: oklch(0.99 0 0);
  --foreground: oklch(0.35 0.02 165.48);
  --card: oklch(1.00 0 0);
  --card-foreground: oklch(0.35 0.02 165.48);
  --popover: oklch(1.00 0 0);
  --popover-foreground: oklch(0.35 0.02 165.48);
  --primary: oklch(0.67 0.17 153.85);
  --primary-foreground: oklch(0.99 0.02 169.99);
  --secondary: oklch(0.90 0.02 238.66);
  --secondary-foreground: oklch(0.20 0.02 266.02);
  --muted: oklch(0.90 0.02 240.73);
  --muted-foreground: oklch(0.50 0.03 268.53);
  --accent: oklch(0.90 0.02 240.73);
  --accent-foreground: oklch(0.35 0.02 165.48);
  --destructive: oklch(0.61 0.24 20.96);
  --border: oklch(0.94 0.01 238.46);
  --input: oklch(0.85 0.02 240.75);
  --ring: oklch(0.67 0.17 153.85);
  --chart-1: oklch(0.67 0.17 153.85);
  --chart-2: oklch(0.50 0.10 270.06);
  --chart-3: oklch(0.72 0.12 201.79);
  --chart-4: oklch(0.80 0.10 100.65);
  --chart-5: oklch(0.60 0.15 300.14);
  --sidebar: oklch(0.98 0.01 238.45);
  --sidebar-foreground: oklch(0.35 0.02 165.48);
  --sidebar-primary: oklch(0.67 0.17 153.85);
  --sidebar-primary-foreground: oklch(0.98 0.01 238.45);
  --sidebar-accent: oklch(0.90 0.02 240.73);
  --sidebar-accent-foreground: oklch(0.35 0.02 165.48);
  --sidebar-border: oklch(0.85 0.02 240.75);
  --sidebar-ring: oklch(0.67 0.17 153.85);
  --destructive-foreground: oklch(1.0000 0 0);
  --font-sans: Lato, sans-serif;
  --font-serif: Merriweather, Geist, Geist Fallback, ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
  --font-mono: Roboto Mono, Geist Mono, Geist Mono Fallback, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  --radius: 0.25rem;
  --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.15 0.02 269.18);
  --foreground: oklch(0.95 0.01 238.46);
  --card: oklch(0.20 0.02 266.02);
  --card-foreground: oklch(0.95 0.01 238.46);
  --popover: oklch(0.20 0.02 266.02);
  --popover-foreground: oklch(0.95 0.01 238.46);
  --primary: oklch(0.67 0.17 153.85);
  --primary-foreground: oklch(0.15 0.02 269.18);
  --secondary: oklch(0.30 0.03 271.05);
  --secondary-foreground: oklch(0.95 0.01 238.46);
  --muted: oklch(0.30 0.03 271.05);
  --muted-foreground: oklch(0.60 0.03 269.46);
  --accent: oklch(0.30 0.03 271.05);
  --accent-foreground: oklch(0.95 0.01 238.46);
  --destructive: oklch(0.64 0.25 19.69);
  --border: oklch(0.95 0.01 238.46 / 15%);
  --input: oklch(0.95 0.01 238.46 / 20%);
  --ring: oklch(0.67 0.17 153.85);
  --chart-1: oklch(0.67 0.17 153.85);
  --chart-2: oklch(0.60 0.10 269.83);
  --chart-3: oklch(0.72 0.12 201.79);
  --chart-4: oklch(0.80 0.10 100.65);
  --chart-5: oklch(0.60 0.15 300.14);
  --sidebar: oklch(0.20 0.02 266.02);
  --sidebar-foreground: oklch(0.95 0.01 238.46);
  --sidebar-primary: oklch(0.67 0.17 153.85);
  --sidebar-primary-foreground: oklch(0.15 0.02 269.18);
  --sidebar-accent: oklch(0.30 0.03 271.05);
  --sidebar-accent-foreground: oklch(0.95 0.01 238.46);
  --sidebar-border: oklch(0.95 0.01 238.46 / 15%);
  --sidebar-ring: oklch(0.67 0.17 153.85);
  --destructive-foreground: oklch(1.0000 0 0);
  --font-sans: Lato, sans-serif;
  --font-serif: Merriweather, Geist, Geist Fallback, ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
  --font-mono: Roboto Mono, Geist Mono, Geist Mono Fallback, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  --radius: 0.25rem;
  --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

Spotify spent years perfecting their interface and testing it with millions of users. That signature green isn't random—it's been A/B tested to death and represents one of the most recognizable brand colors in tech. This theme captures that same sophisticated simplicity.

The dark interface philosophy works because content (music, videos, text) pops against dark backgrounds. Your users don't get eye strain from bright white screens, and important elements like CTAs stand out more dramatically. It's the same reason movie theaters are dark.

Light mode is surprisingly clean too. The green maintains its impact while the overall palette becomes more office-friendly. Most dark-first themes look terrible in light mode, but this one actually works for teams that need both.

What's actually in this theme

Dead simple setup—copy the CSS variables into your globals.css and you're done. The Lato font stack gives you that clean, modern typography that Spotify popularized in the streaming era.

That signature green is perfect for play buttons, active states, premium features, or anything that should feel "live" or energetic. The dark grays create focus without being depressing, and the subtle rounded corners keep everything modern.

All contrast ratios pass WCAG AA standards so you won't run into accessibility issues. Since it uses standard shadcn color tokens, your TypeScript autocomplete for bg-primary, text-foreground, etc. just works.

How to use this in projects

The Spotify green should be your primary action color—think play buttons, "Follow" buttons, premium upgrades, or any CTA that represents the core value of your app. Use it strategically, not everywhere.

The dark grays should dominate the interface. Think content-first design where the interface gets out of the way. This works especially well for media platforms, dashboards with rich content, or any app where you want to create focus.

In practice, embrace the dark aesthetic but keep it sophisticated. This isn't a gaming theme—it's professional entertainment industry design. Clean lines, clear hierarchy, and let that green do the heavy lifting for important actions.

You might also like

FAQ