Join our Discord Community

Marshmallow Shadcn Theme

Soft pastel theme with pink and purple tones for shadcn/ui. Complete design system with light/dark modes. TypeScript ready for React.

Working with shadcn themes?

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

Marshmallow Shadcn Theme

Been working with pastels for years and most themes either look like children's toys or have terrible contrast ratios. This marshmallow theme finally gets soft colors right—friendly without being unprofessional, accessible without looking clinical.

Perfect if you're building consumer apps, creative tools, or any React project where you want users to actually enjoy the interface instead of just tolerate it. The rose pink and purple work especially well for wellness apps, design tools, or anything targeting creative professionals.

Installation

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

Original theme by tweakcn.com

CSS Variables

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

:root {
  --background: oklch(0.97 0.01 264.53);
  --foreground: oklch(0.22 0 0);
  --card: oklch(1.00 0 0);
  --card-foreground: oklch(0.22 0 0);
  --popover: oklch(1.00 0 0);
  --popover-foreground: oklch(0.22 0 0);
  --primary: oklch(0.80 0.14 349.25);
  --primary-foreground: oklch(0 0 0);
  --secondary: oklch(0.94 0.07 98.08);
  --secondary-foreground: oklch(0 0 0);
  --muted: oklch(0.92 0.01 268.52);
  --muted-foreground: oklch(0.34 0 0);
  --accent: oklch(0.83 0.09 248.95);
  --accent-foreground: oklch(0 0 0);
  --destructive: oklch(0.70 0.19 23.19);
  --border: oklch(0.85 0 0);
  --input: oklch(0.85 0 0);
  --ring: oklch(0.83 0.09 248.95);
  --chart-1: oklch(0.80 0.14 349.25);
  --chart-2: oklch(0.77 0.15 306.21);
  --chart-3: oklch(0.83 0.09 248.95);
  --chart-4: oklch(0.88 0.09 66.27);
  --chart-5: oklch(0.94 0.14 130.35);
  --sidebar: oklch(1.00 0 0);
  --sidebar-foreground: oklch(0.22 0 0);
  --sidebar-primary: oklch(0.80 0.14 349.25);
  --sidebar-primary-foreground: oklch(0 0 0);
  --sidebar-accent: oklch(0.83 0.09 248.95);
  --sidebar-accent-foreground: oklch(0 0 0);
  --sidebar-border: oklch(0.85 0 0);
  --sidebar-ring: oklch(0.83 0.09 248.95);
  --destructive-foreground: oklch(1.0000 0 0);
  --font-sans: Gabriela, Geist Fallback, ui-sans-serif;
  --font-serif: Gabriela, Geist Fallback, ui-serif;
  --font-mono: Geist Mono, Geist Mono Fallback, ui-monospace;
  --radius: 0rem;
  --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.22 0 0);
  --foreground: oklch(0.97 0.01 264.53);
  --card: oklch(0.29 0 0);
  --card-foreground: oklch(0.97 0.01 264.53);
  --popover: oklch(0.29 0 0);
  --popover-foreground: oklch(0.97 0.01 264.53);
  --primary: oklch(0.80 0.14 349.25);
  --primary-foreground: oklch(0.22 0 0);
  --secondary: oklch(0.77 0.15 306.21);
  --secondary-foreground: oklch(0.22 0 0);
  --muted: oklch(0.32 0 0);
  --muted-foreground: oklch(0.85 0 0);
  --accent: oklch(0.83 0.09 248.95);
  --accent-foreground: oklch(0.22 0 0);
  --destructive: oklch(0.70 0.19 23.19);
  --border: oklch(0.39 0 0);
  --input: oklch(0.39 0 0);
  --ring: oklch(0.83 0.09 248.95);
  --chart-1: oklch(0.80 0.14 349.25);
  --chart-2: oklch(0.77 0.15 306.21);
  --chart-3: oklch(0.83 0.09 248.95);
  --chart-4: oklch(0.88 0.09 66.27);
  --chart-5: oklch(0.94 0.14 130.35);
  --sidebar: oklch(0.29 0 0);
  --sidebar-foreground: oklch(0.97 0.01 264.53);
  --sidebar-primary: oklch(0.80 0.14 349.25);
  --sidebar-primary-foreground: oklch(0.22 0 0);
  --sidebar-accent: oklch(0.83 0.09 248.95);
  --sidebar-accent-foreground: oklch(0.22 0 0);
  --sidebar-border: oklch(0.39 0 0);
  --sidebar-ring: oklch(0.83 0.09 248.95);
  --destructive-foreground: oklch(1.0000 0 0);
  --font-sans: Gabriela, Geist Fallback, ui-sans-serif;
  --font-serif: Gabriela, Geist Fallback, ui-serif;
  --font-mono: Geist Mono, Geist Mono Fallback, ui-monospace;
  --radius: 0rem;
  --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

After trying probably 20 different pastel themes, most look amazing in Figma mockups but terrible in real apps. Users can't read text, buttons disappear, dark mode looks like someone just inverted a coloring book.

This theme works because the contrast ratios are properly balanced. The rose pink and purple pass WCAG tests without looking clinical or washed out. The dark mode is where most pastel themes die, but these colors actually pop against dark backgrounds instead of vanishing.

Works well on everything from simple landing pages to complex SaaS dashboards. The personality doesn't get in the way of usability, which is the whole point.

What's actually in this theme

Dead simple setup—copy the CSS variables into your globals.css and you're done. No weird config file changes or npm installs. Works with whatever shadcn configuration you already have.

The big win is getting personality without looking amateurish. Most pastel themes either look unprofessional or have terrible accessibility. This one hits the sweet spot—soft and friendly but still passes WCAG AA standards to avoid accessibility audit issues.

Dark mode switches automatically with your existing theme toggle. The pastels maintain proper visual weight against dark backgrounds instead of just disappearing. Great for developers who code in dark mode and get sick of themes that only work in light mode.

Since it uses standard shadcn color tokens, your TypeScript autocomplete for bg-primary, text-foreground, etc. just works. No custom type definitions or weird workarounds.

How to use this in projects

The color scheme is soft rose pink for buttons and CTAs, cream backgrounds, gentle purple for accents. Think "high-end wellness app" not "Valentine's Day massacre." The key is restraint—don't pink everything or you'll lose the sophistication.

Dark mode uses the same rose pink on charcoal backgrounds. Most pastel themes fail here because designers just invert everything, but this uses OKLCH colors so the pastels maintain proper visual weight against dark backgrounds. This consistency makes a huge difference in the overall feel.

In practice, use rose pink sparingly for your main CTAs and important elements. Let the cream and purple do the heavy lifting for backgrounds and secondary stuff. Trust the contrast ratios that are built in rather than second-guessing and making things darker "just to be safe." That usually makes things worse.

You might also like

FAQ