Tailwind CSS Color System: How the Shades Are Generated
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
Tailwind CSS ships with one of the most widely used color systems in web development. Its palette of 22 color families — each divided into 11 shades from 50 to 950 — powers millions of websites and has become a de facto standard for how developers think about color scales. But where do these shades come from, how are they generated, and how can you build your own scales that fit seamlessly into the system? This article answers all of those questions.
Tailwind's Design Philosophy for Color
Tailwind does not use a simple arithmetic approach to shade generation. Instead, the Tailwind team hand-curated every shade in the original palette using a combination of perceptual lightness and aesthetic judgment, with the goal of making shades that are:
- Useful at every step: Each shade from 50 to 950 should be a shade that someone would plausibly want to use — not a gap-filler that ends up unused.
- Consistent across hues: A
500shade of blue should feel equally "medium" in perceived brightness as a500shade of green, even though the underlying hex values are completely different. - WCAG-aware: The darker shades (700–950) should achieve AA contrast against white; the lighter shades (50–200) should achieve AA contrast against black.
This philosophy explains why you cannot generate the Tailwind palette with a simple HSL lightness formula. Hues differ in their inherent perceptual brightness — yellow is intrinsically lighter than blue at the same HSL lightness value — so each color family requires individual tuning.
The 22 Color Families
Tailwind v3 and v4 ship with 22 named color families:
| Family | Representative 500 Value |
|---|---|
| Slate | #64748B |
| Gray | #6B7280 |
| Zinc | #71717A |
| Neutral | #737373 |
| Stone | #78716C |
| Red | #EF4444 |
| Orange | #F97316 |
| Amber | #F59E0B |
| Yellow | #EAB308 |
| Lime | #84CC16 |
| Green | #22C55E |
| Emerald | #10B981 |
| Teal | #14B8A6 |
| Cyan | #06B6D4 |
| Sky | #0EA5E9 |
| Blue | #3B82F6 |
| Indigo | #6366F1 |
| Violet | #8B5CF6 |
| Purple | #A855F7 |
| Fuchsia | #D946EF |
| Pink | #EC4899 |
| Rose | #F43F5E |
Notice the five neutral families (slate through stone): these are not just different saturation levels of the same gray. Each has a distinct hue cast — slate leans blue-gray, stone leans warm brown-gray, neutral is the most pure achromatic. This gives designers choices for environments that call for cool, warm, or neutral tones in their gray scaffolding.
The 11 Shade Steps
Each color family contains eleven shades:
| Step | Intended Use |
|---|---|
| 50 | Very light tints; page backgrounds, subtle dividers |
| 100 | Light tints; card backgrounds, table stripes |
| 200 | Light mid-tones; borders, disabled states |
| 300 | Mid-light; placeholder text on dark backgrounds |
| 400 | Mid-tone; secondary icons, secondary text |
| 500 | "Pure" hue; primary brand color, badges |
| 600 | Dark mid-tone; hover states for 500-colored elements |
| 700 | Dark; primary text on light backgrounds |
| 800 | Very dark; headings, high-emphasis text |
| 900 | Near-black; maximum text contrast |
| 950 | Darkest; added in Tailwind v3.3 for more shadow depth |
The 950 shade was added later because designers found that 900 was sometimes not dark enough for deep shadow effects, especially in dark mode where the surface colors are very dark and need an even deeper shade for layering.
The 500 step is intentionally the "canonical" shade of each color — the one that looks most like what you would expect if someone said "I want blue" or "I want green." All other steps are understood relative to this anchor.
How the Shade Algorithm Works
While Tailwind's colors were hand-curated, the team used a process grounded in the OKLCH color space to maintain perceptual consistency. OKLCH (Oklab Lightness Chroma Hue) is designed so that equal numerical changes in lightness produce equal perceived brightness changes, unlike HSL or RGB where hue shifts dramatically alter the perceived lightness.
The general process for a color family looks like this:
- Choose the 500 value: Define the primary brand color for this family in OKLCH or an equivalent perceptual space.
- Set lightness targets for each step: Map the 11 steps to specific OKLCH lightness values — for example, step 50 might target an OKLCH lightness of 0.97, while step 950 targets 0.13.
- Maintain chroma and hue: Where possible, keep the chroma (saturation) and hue angle constant across steps, adjusting only lightness.
- Hand-adjust for hue shift: Many hues exhibit unwanted hue shifts as they get lighter or darker in OKLCH. Yellow, for example, tends to shift toward green when darkened. Human adjustment is required at each step to correct these shifts.
- Convert to sRGB hex: The final OKLCH values are converted to hex codes for use in CSS.
You can see the result of this process by comparing how the Tailwind palette handles yellow versus blue. Blue's steps shift slightly in temperature (the darkest blues have more indigo character), while yellow's steps shift toward olive when darkened to avoid becoming muddy. These are deliberate perceptual corrections that no pure algorithm would produce automatically.
Use the Color Converter to examine any Tailwind hex value in OKLCH space and observe how lightness, chroma, and hue change across the scale.
Customizing the Tailwind Color Palette
Tailwind v3 (tailwind.config.js)
In Tailwind v3, you extend or replace the palette in tailwind.config.js:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
950: '#082f49',
},
},
},
},
}
Using extend preserves all the built-in colors; replacing theme.colors directly removes them.
Tailwind v4 (CSS-First Configuration)
Tailwind v4 eliminates the JavaScript configuration file. Colors are now defined as CSS custom properties in your main CSS file:
@import "tailwindcss";
@theme {
--color-brand-50: #f0f9ff;
--color-brand-100: #e0f2fe;
--color-brand-200: #bae6fd;
--color-brand-300: #7dd3fc;
--color-brand-400: #38bdf8;
--color-brand-500: #0ea5e9;
--color-brand-600: #0284c7;
--color-brand-700: #0369a1;
--color-brand-800: #075985;
--color-brand-900: #0c4a6e;
--color-brand-950: #082f49;
}
This generates the utility classes bg-brand-50 through bg-brand-950, text-brand-*, border-brand-*, and so on — exactly as the built-in colors work, but with your custom hue.
What Changed in Tailwind v4
Tailwind v4 introduced several significant changes to the color system:
CSS Variables as the Source of Truth
In v4, every built-in color is exposed as a CSS custom property. This means you can access any Tailwind color in plain CSS without Tailwind utility classes:
.custom-element {
background-color: var(--color-blue-500);
border-color: var(--color-blue-200);
}
This was not easily possible in v3 without additional tooling or manually duplicating hex values.
OKLCH Color Values
Tailwind v4 expresses its colors in OKLCH rather than sRGB hex. This has several advantages:
- Wide gamut support: On displays that support P3 or Rec. 2020 gamuts, colors can be more vivid than what hex codes can express.
- Better interpolation: Gradients between two Tailwind colors produce more perceptually uniform results.
- Predictable manipulation: Adjusting lightness in OKLCH is more reliable than adjusting it in HSL.
The change is mostly transparent to developers who use utility classes — bg-blue-500 looks the same — but it matters if you are building custom gradients or animations that interpolate between colors.
Semantic Color Tokens
v4 also introduced better support for semantic color tokens — variables that describe what a color does rather than what it looks like:
@theme {
--color-primary: var(--color-blue-600);
--color-primary-hover: var(--color-blue-700);
--color-surface: var(--color-slate-50);
--color-on-surface: var(--color-slate-900);
}
This pattern maps your design system's semantic layer onto Tailwind's scale layer, giving you the ability to switch themes without changing component markup.
Building a Custom Scale That Fits Tailwind
If you need a custom color that is not in the default palette — your brand's specific orange or a bespoke green — you have two options: find the closest built-in family and adjust, or generate an entirely new scale.
Using the Shade Generator
The Shade Generator produces a complete 50–950 scale from a single input hex code. Enter your brand's primary color and the tool:
- Converts the hex to OKLCH
- Calculates lightness targets for each of the 11 steps
- Adjusts chroma appropriately so lighter shades are less saturated and darker shades maintain depth
- Outputs sRGB hex values ready to paste into your Tailwind config
For example, if your brand color is #0F766E (a teal-green), the generator might produce:
| Step | Hex |
|---|---|
| 50 | #F0FDFA |
| 100 | #CCFBF1 |
| 200 | #99F6E4 |
| 300 | #5EEAD4 |
| 400 | #2DD4BF |
| 500 | #14B8A6 |
| 600 | #0D9488 |
| 700 | #0F766E |
| 800 | #115E59 |
| 900 | #134E4A |
| 950 | #042F2E |
This matches Tailwind's built-in Teal scale, demonstrating that the generator's output aligns with the official palette's visual character.
Using Tailwind Colors for Dark Mode
Tailwind's shade system is well-suited to dark mode because the scale provides mirror-image values. A typical convention:
| Light Mode | Dark Mode | Purpose |
|---|---|---|
slate-50 |
slate-900 |
Page background |
slate-100 |
slate-800 |
Card background |
slate-200 |
slate-700 |
Border |
slate-900 |
slate-100 |
Body text |
blue-600 |
blue-400 |
Primary action |
The key insight is that you invert the shade number rather than the color. Where you use slate-100 in light mode, you use slate-900 in dark mode. For interactive colors like links and buttons, you shift from a darker shade (600) in light mode to a lighter shade (400) in dark mode, maintaining contrast against the different background.
Tailwind's dark: variant makes this systematic:
<div class="bg-slate-50 dark:bg-slate-900 text-slate-900 dark:text-slate-100">
<button class="bg-blue-600 dark:bg-blue-400 text-white dark:text-slate-900">
Action
</button>
</div>
Common Color System Mistakes
Using the Same Shade for Both Modes
Applying bg-blue-600 without a dark: override is a common mistake. In dark mode, dark backgrounds with a bright blue element look fine, but a white card on a dark background becomes jarring. Always define both light and dark variants for background colors.
Picking Non-Adjacent Shades for Contrast
Using gray-400 text on a gray-300 background creates insufficient contrast. A general rule: maintain at least a 4-step gap between foreground and background shades (e.g., text on slate-100 should be at least slate-700). Use the Contrast Checker to verify specific combinations meet WCAG AA (4.5:1) or AAA (7:1).
Using Too Many Color Families
The Tailwind palette has 22 families, but most interfaces need three at most: one for neutrals (gray/slate), one for the primary brand color, and one for semantic states (red for errors, green for success, yellow for warnings). Picking four or more distinct colored families creates visual complexity without purpose.
Key Takeaways
- Tailwind CSS ships with 22 color families, each containing 11 shades from 50 to 950, produced through perceptual lightness analysis and human curation rather than a simple arithmetic formula.
- The five neutral families (slate, gray, zinc, neutral, stone) each have distinct hue casts, giving designers warm, cool, or neutral gray options.
- The 500 step is the canonical "pure" shade for each color family; all other steps are understood relative to it, and the 950 step was added in v3.3 for deeper shadow and dark-surface layering.
- Tailwind v4 moves to CSS-first configuration with
@theme, exposes all colors as CSS custom properties, and uses OKLCH internally for better perceptual uniformity and wide-gamut support. - The Shade Generator produces a complete Tailwind-compatible 50–950 scale from any input hex code, using OKLCH-based lightness targets.
- For dark mode, invert the shade number (50 ↔ 900) rather than inverting the hue, and shift interactive colors from darker shades (600) to lighter shades (400) to maintain contrast against dark backgrounds.