Designing Custom Tailwind Palettes

May 28, 20266 min read

Why Custom Palettes Matter

Tailwind's default palette is excellent for prototyping, but production products need brand-specific colors. A custom palette ensures visual consistency across your entire application and makes your product recognizable. Rather than overriding Tailwind utilities ad hoc, define a complete palette that integrates with Tailwind's token system.

Tailwind Color Configuration

Basic Custom Colors

// tailwind.config.ts
export default {
  theme: {
    extend: {
      colors: {
        brand: {
          50:  '#f0f5ff',
          100: '#e0ebff',
          200: '#c2d6ff',
          300: '#94b8ff',
          400: '#6699ff',
          500: '#3366ff',
          600: '#1a4fff',
          700: '#0033cc',
          800: '#002699',
          900: '#001a66',
          950: '#000d33',
        },
      },
    },
  },
}

This gives you bg-brand-500, text-brand-700, border-brand-200, and every other Tailwind color utility — automatically.

Multi-Brand Palettes

For products with distinct color families:

colors: {
  brand: { /* primary blue */ },
  accent: { /* secondary orange */ },
  surface: { /* neutral backgrounds */ },
  feedback: {
    success: '#16a34a',
    warning: '#d97706',
    error: '#dc2626',
    info: '#2563eb',
  },
}

Generating Shade Scales

The hardest part of custom palettes is generating consistent shade scales. A good scale progresses smoothly from very light to very dark while maintaining the same hue identity.

The OKLCH Approach

OKLCH is a perceptually uniform color space — equal numeric steps produce equal visual steps. This makes it ideal for generating shade scales:

/* Define your brand color in oklch */
:root {
  --brand-500: oklch(0.55 0.2 260);
}

From a single oklch anchor, you can derive a full scale by adjusting lightness while keeping chroma and hue constant:

ShadeLightnessResult
500.97Very light tint
1000.93Light tint
2000.85Soft shade
3000.75Medium-light
4000.65Medium
5000.55Base color
6000.45Medium-dark
7000.37Dark
8000.28Very dark
9000.22Near black
9500.15Deepest shade
// Generate shades from an oklch base
function generateShades(L, C, H) {
  const lightnesses = [0.97, 0.93, 0.85, 0.75, 0.65, 0.55, 0.45, 0.37, 0.28, 0.22, 0.15]
  return lightnesses.map(l => `oklch(${l} ${C} ${H})`)
}

Hex Fallbacks

OKLCH browser support is growing but not universal. Generate hex values for your Tailwind config and deliver oklch via CSS custom properties for progressive enhancement:

:root {
  --brand-500: #3366ff;           /* Fallback */
  --brand-500: oklch(0.55 0.2 260); /* Modern browsers override */
}

Design Token Architecture

CSS Custom Properties as Source of Truth

/* app/assets/css/main.css */
:root {
  /* Brand palette */
  --color-brand-50: oklch(0.97 0.02 260);
  --color-brand-500: oklch(0.55 0.2 260);
  --color-brand-900: oklch(0.22 0.15 260);

  /* Semantic tokens */
  --color-bg-primary: var(--color-brand-50);
  --color-text-primary: var(--color-brand-900);
  --color-interactive: var(--color-brand-500);
}

.dark {
  --color-bg-primary: var(--color-brand-950);
  --color-text-primary: var(--color-brand-50);
  --color-interactive: var(--color-brand-400);
}

Mapping Tokens to Tailwind

// tailwind.config.ts
export default {
  theme: {
    extend: {
      colors: {
        bg: {
          primary: 'var(--color-bg-primary)',
        },
        text: {
          primary: 'var(--color-text-primary)',
        },
        interactive: 'var(--color-interactive)',
        brand: {
          50: 'var(--color-brand-50)',
          500: 'var(--color-brand-500)',
          900: 'var(--color-brand-900)',
        },
      },
    },
  },
}

Dark Mode Palette Design

Dark mode is not just inverted light mode. Key principles:

  • Don't switch to pure black — use your darkest brand shade or a dark neutral like slate-900
  • Reduce chroma — saturated colors appear to vibrate on dark backgrounds. Drop chroma by 15–20% in dark mode
  • Increase lightness gap — on dark backgrounds, you need more contrast between text and surface than on light backgrounds
  • Test both themes simultaneously — design components that look correct in both modes

Validation Checklist

Before shipping a custom palette:

  • Every text color meets 4.5:1 contrast against its background (both themes)
  • The scale steps are perceptually even (no jarring jumps)
  • Brand colors are distinguishable under color vision deficiency simulation
  • Dark mode palette doesn't cause eye strain (no saturated-on-dark combinations)
  • All shades are used — if 100 and 200 are too similar, collapse them
  • CSS custom properties and Tailwind config values stay in sync

Try It Yourself

Design and preview custom color palettes with live shade generation. Export directly to Tailwind config or CSS custom properties.

👉 Color Palette Generator