CColorWell
Get ColorWell

ColorWell/Guides

How to Create a Good Color Palette for Design Systems

Learn to build harmonized color palettes from a base hex, verify WCAG contrast instantly, and export tokens for CSS or Figma in one workflow.

October 9, 2026 · 5 min read

A good color palette starts with one deliberate base color, then expands into a harmonized scale of tints and shades that maintain perceptual consistency. Verify that every text-background pair meets accessibility standards before exporting the values as named tokens for your design system. This approach ensures visual harmony and functional readability without manual trial-and-error.

Start with a Base Color

Every palette needs an anchor. Choose one primary hue that reflects your brand’s personality—trustworthy blues, energetic oranges, calm greens—and commit to its hex value. Avoid picking a color that is too bright or too dark initially; mid-range saturation usually offers the most flexibility for later adjustments. For this guide, we use #4F46E5, a balanced indigo that works well for both buttons and headings.

Once you have your base hex, resist the urge to manually tweak lightness and saturation in a standard RGB slider. These tools often cause hue shifts, making your lighter shades look washed-out yellow and your darker shades look muddy purple. Instead, use a method that preserves the hue while adjusting brightness and saturation independently. This is where perceptual color spaces like Oklch excel, ensuring that your indigo stays indigo across the entire scale. If you want to speed up this harmonization step, ColorWell generates these variations automatically while keeping the hue locked.

Generate Harmonized Variations

A robust design system needs more than one shade. You need a scale that handles backgrounds, borders, hover states, and active states. A standard approach is to create ten steps, ranging from a very light background tint (often labeled 50) to a deep, high-contrast text color (often labeled 900).

Using #4F46E5 as our base, we generate a monochromatic scale. The goal is to lighten the color for backgrounds and darken it for text, while keeping the saturation high enough to remain vibrant. Below is the resulting scale, generated by adjusting lightness and chroma in a perceptual space to prevent hue drift.

TokenHex ValueTypical Use Case
indigo-50#EEF2FFPage background, subtle cards
indigo-100#E0E7FFHover states, light borders
indigo-200#C7D2FESecondary buttons, inputs
indigo-300#A5B4FCIcons, secondary text
indigo-400#818CF8Links, active states
indigo-500#6366F1Primary buttons, headings
indigo-600#4F46E5Base color, strong accents
indigo-700#4338CADarker headings, borders
indigo-800#3730A3Footer backgrounds
indigo-900#312E81High-contrast text

Notice how indigo-50 is nearly white but retains a cool blue undertone, while indigo-900 is deep but still reads as blue, not black. This consistency is critical for a cohesive interface. If you were to lighten #4F46E5 using simple RGB math, indigo-50 might end up looking grayish or teal, breaking the visual link to the brand color.

Verify WCAG Contrast Automatically

Color harmony is useless if your text is unreadable. You must check every combination of foreground and background against WCAG AA and AAA standards. AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text. AAA is stricter, requiring 7:1 and 4.5:1 respectively.

Let’s test our indigo scale against white (#FFFFFF) text, a common scenario for buttons and headers.

  1. indigo-50 (#EEF2FF) with White Text: Contrast ratio is approximately 1.1:1. Fail. This combination is illegible. Use dark text on light backgrounds.
  2. indigo-600 (#4F46E5) with White Text: Contrast ratio is approximately 4.8:1. Pass AA. Suitable for standard buttons and headings.
  3. indigo-900 (#312E81) with White Text: Contrast ratio is approximately 8.5:1. Pass AAA. Excellent for small body text on dark backgrounds.

When building your palette, you should run these checks for every pair you intend to use. Doing this manually for ten shades takes time, but it prevents costly accessibility issues later. Many designers use tools that calculate these ratios instantly as they adjust colors, ensuring that no combination is overlooked. For instance, ColorWell runs these AA and AAA verdicts automatically for every color pair in your generated palette, so you know immediately if your indigo-200 background works with indigo-900 text.

Name Tokens for Readability

Hex codes are precise but hard to remember. "Use #4F46E5 for buttons" is less effective than "Use indigo-600 for buttons." Naming tokens creates a shared language for your team. It also makes your code more maintainable. If you change the brand color, you update the definition of indigo-600, and every component using that token updates automatically.

Follow a consistent naming convention. The most common pattern is [hue]-[weight]. For our indigo palette, we used indigo-50 through indigo-900. This tells the developer exactly how dark or light the color is relative to the others. Avoid semantic names like primary-button or header-bg for the base tokens. Instead, keep the color names descriptive of the color itself, and apply semantic aliases in your component styles if needed.

Here is how you might structure these names in a CSS variable file:

:root {
  /* Indigo Scale */
  --color-indigo-50: #EEF2FF;
  --color-indigo-100: #E0E7FF;
  --color-indigo-200: #C7D2FE;
  --color-indigo-300: #A5B4FC;
  --color-indigo-400: #818CF8;
  --color-indigo-500: #6366F1;
  --color-indigo-600: #4F46E5;
  --color-indigo-700: #4338CA;
  --color-indigo-800: #3730A3;
  --color-indigo-900: #312E81;
}

This structure is readable and scalable. If you add a new hue, say a neutral slate, you follow the same pattern: slate-50, slate-100, and so on. This predictability helps new team members onboard quickly.

Export to Your Design Tool

Once your palette is harmonized and verified, you need to get it into your workflow. Copying hex codes one by one is tedious and error-prone. Look for tools that allow you to export the entire scale in formats compatible with your stack. Common formats include CSS variables, Tailwind config objects, JSON for design tokens, and Figma styles.

For our indigo example, here is the Tailwind configuration snippet. This allows developers to use classes like bg-indigo-500 or text-indigo-900 directly in their HTML.

module.exports = {
  theme: {
    extend: {
      colors: {
        indigo: {
          50: '#EEF2FF',
          100: '#E0E7FF',
          200: '#C7D2FE',
          300: '#A5B4FC',
          400: '#818CF8',
          500: '#6366F1',
          600: '#4F46E5',
          700: '#4338CA',
          800: '#3730A3',
          900: '#312E81',
        },
      },
    },
  },
}

If you are working in Figma, you can paste these values as shared styles. Ensure your design tool supports variable modes for light and dark themes if you plan to support both. For example, indigo-50 might be the background in light mode, but indigo-900 becomes the background in dark mode. Your exported tokens should account for these shifts.

When exporting, double-check that the hex values match your verified contrast tests. Some tools round colors differently, which can slightly alter contrast ratios. Always test the final output in your actual application environment. If you use a tool like ColorWell, the export feature copies these exact values to your clipboard, ensuring consistency between your design file and your codebase. This direct transfer reduces friction and keeps your design system aligned across platforms.

Do it in ColorWell

Everything in this guide works in the browser — open the tool and try it on your own input.

Open ColorWell →

Questions people also ask

What is the best color space for palettes?

Use a perceptual color space like Oklch to generate harmonized scales. This prevents unwanted hue shifts, ensuring that lighter shades remain vibrant and darker shades stay true to the base color rather than becoming washed-out or muddy.

How many colors should a brand palette have?

A standard robust palette typically includes ten steps, ranging from light backgrounds (step 50) to high-contrast text colors (step 900). This range provides sufficient variation for backgrounds, borders, hover states, and active elements while maintaining visual consistency.

Can I edit the generated hex codes?

Yes, you can manually edit the generated hex codes to fine-tune specific shades. However, it is recommended to adjust lightness and saturation within a perceptual space to maintain hue consistency across the entire scale.

More guides