Tailwind CSS ships with an impressive built-in color palette - 22 named hues, each spanning 11 shades from 50 to 950. But real-world projects have brand colors, design systems, and accessibility requirements that go beyond what any generic palette can offer. In this guide you'll learn how to extend, override, and fully control Tailwind's color system to fit any project.
1. Why Tailwind's Default Palette Isn't Enough
Tailwind's default palette is excellent as a starting point, but it was designed to be generic and broadly applicable. The moment you're building a product with a brand identity - a specific teal that matches your logo, a warm neutral that feels premium, or a red that meets WCAG contrast on dark backgrounds - you'll hit the limits of the defaults.
Common pain points with the default palette include:
- Brand mismatch: Your brand blue is
#1a4fd6, not Tailwind'sblue-600(#2563eb). Close, but not production-ready. - Missing semantic names: Utility classes like
bg-blue-600have no semantic meaning. Renaming tobg-brand-primarymakes code self-documenting. - No design token integration: Modern design systems use tokens (e.g. Figma variables) that map to specific values - not framework-specific shade numbers.
- Accessibility constraints: You may need a custom scale where the contrast between 400 and 600 is guaranteed to pass AA/AAA standards at your specific background colors.
The good news: Tailwind's configuration system is built for exactly this. You have full control over every color, shade, and semantic alias.
2. Understanding Tailwind's Color Scale (50–950)
Tailwind uses a numeric scale system where each number represents a perceptual step in lightness. The scale runs from 50 (nearly white) through 950 (nearly black), with 11 stops in between: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950.
| Shade | Use Case | Example (Indigo) |
|---|---|---|
| 50 | Background tints, hover surfaces | #eef2ff |
| 100 | Light backgrounds, badges | #e0e7ff |
| 200 | Borders, dividers on light BG | #c7d2fe |
| 300 | Disabled states, placeholders | #a5b4fc |
| 400 | Secondary text on white | #818cf8 |
| 500 | Brand color baseline | #6366f1 |
| 600 | Primary buttons, links | #4f46e5 |
| 700 | Hover states on buttons | #4338ca |
| 800 | Dark text, dark card BGs | #3730a3 |
| 900 | Headings on dark mode | #312e81 |
| 950 | Near-black tones | #1e1b4b |
The 500 shade is always the "pure" hue - your base color at full saturation. Shades below 500 mix in white; shades above 500 mix in black (though the exact method Tailwind uses is more perceptually nuanced than simple tinting).
3. Adding Custom Colors in tailwind.config.js
Tailwind's tailwind.config.js file has a theme key with two ways to customize colors:
theme.extend.colors- adds your colors alongside the defaults (recommended)theme.colors- replaces the entire palette (use only if you want full control)
Example: Adding a brand color with a full scale
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: '#f0f4ff',
100: '#dce6fe',
200: '#b9cdfd',
300: '#87a9fb',
400: '#5480f7',
500: '#2a56f0', // base brand color
600: '#1a40d6',
700: '#1433ae',
800: '#102a8c',
900: '#0d2370',
950: '#071247',
},
// Semantic aliases (reference brand scale)
primary: 'var(--color-primary)',
surface: {
DEFAULT: '#ffffff',
dark: '#0f172a',
},
},
},
},
};You can now use bg-brand-500, text-brand-700, border-brand-200, etc., throughout your project.
For Tailwind v4 (CSS-first config):
/* app.css - Tailwind v4 uses CSS variables natively */
@import "tailwindcss";
@theme {
--color-brand-50: #f0f4ff;
--color-brand-500: #2a56f0;
--color-brand-950: #071247;
--color-primary: var(--color-brand-500);
}4. Generating a Full 50–900 Scale from One Base Color
Manually picking 11 harmonious shades for every brand color is time-consuming and inconsistent. The better approach: start with your one brand hex and generate the entire scale algorithmically.
This is exactly what ColorPeek's Tint & Shade Generator does. Enter your base hex, and it produces a perceptually uniform scale that you can copy directly into your Tailwind config.
How the scale generation works:
- Convert your base hex to HSL (Hue, Saturation, Lightness)
- Keep the hue fixed across all 11 stops
- Apply a lightness curve: shade 50 → L 97%, shade 500 → base L, shade 950 → L 8%
- Adjust saturation slightly - tints desaturate a bit, shades stay punchy
- Convert each stop back to hex for Tailwind compatibility
// Result of generating a scale from #2a56f0:
// Paste directly into tailwind.config.js
brand: {
50: '#eef2ff', // L: 96%
100: '#dce6fe', // L: 92%
200: '#b9cdfd', // L: 84%
300: '#87a9fb', // L: 74%
400: '#5480f7', // L: 63%
500: '#2a56f0', // L: 55% ← your base
600: '#1a40d6', // L: 46%
700: '#1433ae', // L: 37%
800: '#102a8c', // L: 29%
900: '#0d2370', // L: 22%
950: '#071247', // L: 14%
}The key advantage of a generated scale over manually chosen values is perceptual uniformity - the visual step between adjacent shades feels equal, which makes your UI look polished and intentional.
5. Design Tokens vs. Utility Classes
A design token is a named variable that stores a design decision - color.brand.primary, color.surface.default,spacing.layout.gutter. Utility classes like bg-indigo-600 are implementation details; tokens are the intent.
Without Tokens
<button class="bg-indigo-600
hover:bg-indigo-700
text-white">
Submit
</button>
<!-- If brand changes to teal,
update every file -->With Tokens
<button class="bg-primary
hover:bg-primary-dark
text-on-primary">
Submit
</button>
<!-- Change token once,
updates everywhere -->In Tailwind, you can bridge the gap by defining semantic token names in your config that reference your scale:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
// Raw scale (generated from one hex)
brand: { 50: '...', 500: '#2a56f0', 950: '...' },
// Semantic tokens that reference the scale
primary: ({ theme }) => theme('colors.brand.500'),
'primary-dark': ({ theme }) => theme('colors.brand.700'),
'on-primary': '#ffffff',
surface: ({ theme }) => theme('colors.brand.50'),
'surface-dark': ({ theme }) => theme('colors.brand.950'),
},
},
},
};6. Exporting Your Palette as Tailwind Config
Once you've built and refined your color palette - whether in ColorPeek's palette builder, a Figma file, or by hand - the final step is exporting it in a format you can paste directly into your project.
ColorPeek's Palette Exporter supports multiple output formats from a single palette:
- Tailwind config -
theme.extend.colorsobject - Tailwind v4 CSS -
@themeblock with CSS variables - CSS custom properties - for any CSS framework or vanilla projects
- SCSS variables - for SASS-based projects
- JSON / Style Dictionary - for design token pipelines
- Figma tokens plugin format - for design-to-code sync
/* Exported as CSS custom properties */
:root {
--color-brand-50: #eef2ff;
--color-brand-100: #dce6fe;
--color-brand-200: #b9cdfd;
--color-brand-300: #87a9fb;
--color-brand-400: #5480f7;
--color-brand-500: #2a56f0;
--color-brand-600: #1a40d6;
--color-brand-700: #1433ae;
--color-brand-800: #102a8c;
--color-brand-900: #0d2370;
--color-brand-950: #071247;
}7. Key Takeaways
- 1Use theme.extend.colors to add brand colors without losing Tailwind defaults.
- 2The numeric scale (50–950) maps to perceptual lightness steps - 500 is always your base hue.
- 3Generate a full 11-shade scale from one hex using ColorPeek's Tint & Shade Generator for visual consistency.
- 4Layer semantic token names on top of your raw scale - change one value, update the whole product.
- 5Export in multiple formats (Tailwind config, CSS vars, SCSS, JSON) so every tool in your pipeline stays in sync.
- 6Tailwind v4 replaces tailwind.config.js with a CSS-first @theme block - plan your token architecture accordingly.
Share this article
Build Your Tailwind Palette in Seconds
Enter one hex color and get a complete 11-shade scale ready to paste into your Tailwind config. Then export in any format you need.