Add custom colors to Tailwind CSS by defining them in the theme.extend.colors object of your tailwind.config.js file. You can use hex codes, HSL values, or Oklch color spaces, but using a structured naming convention like indigo-500 keeps your markup readable and consistent across large projects.
Why Custom Color Tokens Matter
Default Tailwind palettes are excellent starting points, but they rarely match a specific brand identity perfectly. When you define custom colors, you create a single source of truth for your design system. This ensures that your primary button color is exactly the same everywhere, regardless of which developer is building the component. Without custom tokens, you end up with slight variations in hex codes across different files, leading to visual inconsistencies that are hard to debug. By centralizing these values, you make future theme updates much faster and less error-prone.
Generating a Harmonized Palette
Starting with a single brand color, you need a full scale of shades to handle hover states, backgrounds, and borders. Doing this manually often results in colors that drift in hue when lightened or darkened. For our worked example, we start with the brand hex #4F46E5. To get a professional result, we need a scale that maintains perceptual uniformity. This is where ColorWell helps by generating harmonized Oklch palettes that stay true to the original hue while adjusting lightness and chroma.
Below is the resulting Oklch scale for our indigo brand color. These values are chosen to ensure smooth transitions and distinct contrast levels.
/* Example of Oklch values for an indigo scale */
--color-indigo-50: oklch(0.97 0.02 260);
--color-indigo-100: oklch(0.94 0.04 260);
--color-indigo-200: oklch(0.88 0.06 260);
--color-indigo-300: oklch(0.80 0.08 260);
--color-indigo-400: oklch(0.70 0.10 260);
--color-indigo-500: oklch(0.60 0.12 260); /* Base brand color */
--color-indigo-600: oklch(0.50 0.14 260);
--color-indigo-700: oklch(0.42 0.16 260);
--color-indigo-800: oklch(0.35 0.18 260);
--color-indigo-900: oklch(0.28 0.20 260);
If you prefer standard hex codes for broader compatibility, the corresponding hex values for this scale would be generated from these Oklch coordinates. The key is ensuring that indigo-500 remains your primary interaction color, while lighter shades handle backgrounds and darker shades handle text or borders.
Verifying Contrast for Accessibility
Custom colors must meet accessibility standards. Text placed on your background colors needs sufficient contrast to be readable. WCAG AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text. When you generate a palette, you should verify these ratios for every combination you plan to use. For instance, dark text on indigo-50 should pass easily, but white text on indigo-500 needs checking.
In our example, indigo-500 (#4F46E5) has a contrast ratio of approximately 6.3:1 against white text, which comfortably passes AA standards for normal text. However, lighter shades like indigo-400 might fail against white text depending on the exact hue adjustment. Always test your specific combinations. If a pair fails, lighten the background or darken the text until it passes. This step prevents usability issues later in development.
Exporting to Tailwind Config
Once you have your scale, you need to integrate it into your Tailwind configuration. The most common method is extending the default theme. This allows you to keep Tailwind’s default colors while adding your custom ones. Open your tailwind.config.js file and locate the theme object. Inside theme, find or create the extend object, and then add your colors to the colors object within extend.
Here is the exact configuration block for our indigo example. Paste this directly into your config file.
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
indigo: {
50: '#f5f3ff',
100: '#ede9fe',
200: '#ddd6fe',
300: '#c4b5fd',
400: '#a78bfa',
500: '#8b5cf6',
600: '#7c3aed',
700: '#6d28d9',
800: '#5b21b6',
900: '#4c1d95',
950: '#2e1065',
},
},
},
},
plugins: [],
}
Note that this example uses standard hex values for simplicity. If you are using Oklch, you can replace the hex strings with the oklch(...) syntax shown earlier. Modern browsers support Oklch well, but check your support targets if you need to support older browsers.
Applying Tokens in Your Components
With the config in place, you can now use these colors in your HTML classes. Tailwind generates utility classes based on your config keys. For our indigo scale, you will have classes like text-indigo-500, bg-indigo-50, and border-indigo-200. These classes work exactly like the default Tailwind colors.
Consider a button component. You might want a solid background with white text. Use bg-indigo-500 for the background and text-white for the text. For a hover state, darken the background slightly using hover:bg-indigo-600. This creates a consistent interaction pattern. If you need a subtle background for a card, use bg-indigo-50. The naming convention makes these choices intuitive. You don’t need to remember hex codes; you just pick the shade that looks right.
Best Practices for Color Naming
Naming your custom colors effectively prevents confusion. Avoid names like blue-light or blue-dark because they are vague and can conflict with future additions. Instead, use numeric scales like indigo-50 through indigo-950. This mirrors Tailwind’s default naming and is familiar to developers. It also implies a hierarchy: lower numbers are lighter backgrounds, higher numbers are darker text or accents.
If you have multiple brand colors, give them distinct names like primary, secondary, and accent, each with their own numeric scale. This separates semantic roles from specific hues. For example, primary-500 tells a developer this is the main action color, regardless of whether it is blue, green, or orange. This abstraction makes theme switching easier if you ever change your brand colors. Keep your names short and consistent across all files.
When you need to adjust colors for dark mode, use the same scale but invert the usage logic. Light backgrounds become dark backgrounds, and dark text becomes light text. Your config supports this automatically if you use the dark: variant. For example, bg-white dark:bg-indigo-900 ensures readability in both modes. By sticking to a structured scale, you minimize the effort required to maintain accessibility across different themes.