Sure, there are tools out there that will generate for you a color palette for a given color. But will you want to manually generate it again and copy the hex values every time you update the color?
No.
Tailwind CSS gives us the ability to generate dynamic palettes, although it requires a little JavaScript function to make it work.
Start with defining a root color
The trick is to work with HSL values.
Let's say we want to have a palette from the color #0c8a4b
and call it primary
. The first step is to get the HSL values. To get them, we can use this color converter website https://convertacolor.com/ or any color picker like the one in the browser's DevTools.
In the HEX field, we enter #0c8a4b
.
It will give us in return a HSL field containing hsl(150,84%,29.4%)
.
Now in our CSS file, we define our base color:
:root {
--color-primary-h: 150;
--color-primary-s: 84%;
--color-primary-l: 29.4%;
}
Be careful, the first value H
is not a percentage.
Extend Tailwind CSS config
In our tailwind.config.js
file, we'll add a small function at the top:
function dynamicHsl(h, s, l) {
return ({ opacityVariable, opacityValue }) => {
if (opacityValue !== undefined) {
return `hsla(${h}, ${s}, ${l}, ${opacityValue})`
}
if (opacityVariable !== undefined) {
return `hsla(${h}, ${s}, ${l}, var(${opacityVariable}, 1))`
}
return `hsl(${h}, ${s}, ${l})`
}
}
This function will convert 3 given HSL values into a CSS property. Thanks to Tailwind CSS 2.0 and above, our generated color palette will also be able to take opacity into account.
And now we extend the theme using this new function:
module.exports = {
theme: {
extend: {
colors: {
primary: {
DEFAULT: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'var(--color-primary-l)'),
100: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) + 30%)'),
200: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) + 24%)'),
300: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) + 18%)'),
400: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) + 12%)'),
500: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) + 6%)'),
600: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'var(--color-primary-l)'),
700: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) - 6%)'),
800: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) - 12%)'),
900: dynamicHsl('var(--color-primary-h)', 'var(--color-primary-s)', 'calc(var(--color-primary-l) - 18%)'),
},
},
},
},
};
By varying the L
value alone, the palette will keep a monochromatic look, going from light to dark. Exactly what we want.
Enjoy
This will give us these new utility classes to use where we want:
- text-primary (same as text-primary-600)
- text-primary-100 to text-primary-900
And following the same pattern:
- bg-primary
- border-primary
- ring-primary
- etc.
You can also combine these values with opacity, for instance class="border border-primary border-opacity-25"
.
Go further
This technique works best when the base color is not too clear and not too dark. Try other percentage values than +30% to -18% and experiment with what better fits your needs.
Top comments (4)
I little bit upgrade your code:
Now all we need to put color name like that:
Awesome and thanks for the tips.
Q: are there a way to use lightness as a modifier in tailwind?
Ex: for now we I have acces to alpha: text-primary-500/20 where 20 is alpha/opacity value. I would like to have text-primary/10/20 where 10 is lightening increase from primary and 20 is alpha/opacity.
Thank you
Can someone explain me how these parameters are passed in returning function
return ({ opacityVariable, opacityValue }) => {
awesome!