A color palette generator for a website should do three things: turn one brand hex code into a harmonized scale, verify every text-on-background pair against WCAG standards, and export the result as ready-to-use CSS or Tailwind tokens. Doing this before you write component code prevents the most common design failure—a palette that looks great in a mockup but becomes unreadable or inaccessible in production.
Why You Need a Dedicated Palette Generator
Manual color picking is risky because human eyes are poor judges of mathematical contrast. You might select a blue that looks vibrant against white, but if the luminance difference is too low, it fails accessibility standards. A dedicated generator solves this by calculating relative luminance and contrast ratios automatically.
It also ensures that variations of your color—like hover states or disabled buttons—maintain the same hue while adjusting only lightness and saturation. This prevents the "muddy" look that happens when you manually mix colors in RGB space, where lightening a color often shifts its hue unintentionally.
Step 1: Define Your Brand Base Color
Your base color is the anchor. It should be the primary brand color, not a shade you use for a specific button. For this guide, we will use #4F46E5, a vibrant indigo often used for primary actions. This is a mid-range lightness color, which makes it an excellent starting point because it requires adjustment for both light and dark backgrounds.
When choosing a base, avoid extremes. Pure black (#000000) and pure white (#FFFFFF) are rarely good base colors because they lack hue information. Instead, pick a color that represents your brand’s energy. If you are unsure, start with a color that passes AA contrast against white. If it does not, you will need to darken it before building your full palette.
Step 2: Generate Harmonized Schemes
Once you have your base, you need a scheme. A monochromatic scheme is the safest bet for websites because it relies on variations of a single hue, ensuring visual consistency. This involves creating tints (lighter versions) and shades (darker versions) of your base color.
Using a tool like ColorWell, you drop in #4F46E5 and select the monochromatic option. The tool generates a scale from very light to very dark. Here is what the resulting scale looks like when exported as CSS variables. Note how the hue remains consistent while lightness changes.
:root {
--color-primary-50: #eef2ff;
--color-primary-100: #e0e7ff;
--color-primary-200: #c7d2fe;
--color-primary-300: #a5b4fc;
--color-primary-400: #818cf8;
--color-primary-500: #6366f1;
--color-primary-600: #4f46e5; /* Base Color */
--color-primary-700: #4338ca;
--color-primary-800: #3730a3;
--color-primary-900: #312e81;
--color-primary-950: #1e1b4b;
}
This scale is usable immediately. --color-primary-600 is your base. --color-primary-50 is likely your background tint. --color-primary-900 is your text color on light backgrounds.
Step 3: Verify WCAG Contrast Instantly
Do not assume the scale is accessible. You must check every pair you plan to use. The two critical checks are body text on background and button text on button background.
For our example, we need to check #4F46E5 (our base) against white (#FFFFFF) and against a light gray background (#F3F4F6).
| Foreground | Background | Contrast Ratio | AA Normal (4.5:1) | AA Large (3:1) |
|---|---|---|---|---|
#4F46E5 | #FFFFFF | 6.29:1 | Pass | Pass |
#4F46E5 | #F3F4F6 | 5.7:1 | Pass | Pass |
#FFFFFF | #4F46E5 | 6.29:1 | Pass | Pass |
#312E81 | #FFFFFF | 11.4:1 | Pass | Pass |
In this scenario, the base color passes AA for normal text on white. However, if you had chosen a lighter blue like #818CF8, it would fail against white. This is why verification is non-negotiable. If a pair fails, darken the foreground or lighten the background until it passes. Do not rely on "visual preference" if it fails the math.
Step 4: Export to CSS and Tailwind
Once verified, export the tokens. You want named tokens, not hex codes, in your stylesheet. This makes your code readable and maintainable. If you use Tailwind CSS, you can export the configuration directly.
Here is the Tailwind config export for the palette above. This allows you to use classes like text-primary-600 or bg-primary-50 in your markup.
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b',
},
},
},
},
}
If you are not using Tailwind, use the CSS variable block from Step 2. The key is consistency. Ensure that the names in your CSS match the names in your component library. If you have a button component, it should reference var(--color-primary-600), not #4F46E5.
Common Mistakes to Avoid
Ignoring the dark mode counterpart. A palette that works on white often fails on dark gray. You need a separate scale for dark mode, typically using the lighter end of your monochromatic range for text and the darker end for backgrounds. Test #FFFFFF on #1e1b4b (our --color-primary-950) to ensure it passes.
Using mid-tones for text. Colors like --color-primary-500 (#6366f1) sit in a risky middle ground: they often fail WCAG AA for normal body text on white backgrounds while passing on black. Reserve mid-tones for accents, borders, or icons. Use the extreme ends of your scale (50-100 for light backgrounds, 800-950 for dark text) for readability.
Forgetting UI components. Contrast rules apply to borders, icons, and focus states, not just text. A button border must be visible against the background. Check the contrast between your button border color and the page background. If it is too low, the button will look "ghosted" or invisible to users with low vision.
Relying on RGB adjustments. When lightening a color, do not just add white in RGB space. This shifts the hue. Use a tool that works in perceptual color spaces like Oklch. This ensures that --color-primary-100 looks like a light version of --color-primary-600, not a different color entirely.