Navigate back to the homepage

How to whitelist dynamic Tailwind classes in PurgeCSS

Frederick Morin
December 13th, 2019 · 1 min read

I was building an array of colorful tags to use in my PortfolioCard components.

Since many cards could share the same tags, I didn’t want to declare colors in my data. It would have led to repetition that would be problematic if I ever needed to change them.

I opted instead to use Gatsby’s Node APIs to transform my array of tag names into an array of objects at build time.

I’d maintain an object whose keys correspond to the tag names in my data, and whose values are an array, where the first item is a background color and the second is a text color:

1const TAG_COLORS = {
2 javascript: ['bg-yellow-vivid-400', 'text-gray-900'],
3 react: ['bg-blue-400', 'text-gray-900'],
4 gatsby: ['bg-purple-700', 'text-purple-100'],
5 ...
6};

So this JSON data:

1"tags": ["javascript", "react", "gatsby", "jest"]

is converted into this JavaScript array to be consumed by my Tags component:

1[
2 { name: 'javascript', color: ['bg-yellow-vivid-400', 'text-gray-900'] },
3 { name: 'react', color: ['bg-blue-400', 'text-gray-900'] },
4 { name: 'gatsby', color: ['bg-purple-700', 'text-purple-100'] },
5 { name: 'jest', color: ['bg-red-vivid-800', 'text-white'] },
6];

Here’s what the rendered component looks like:

javascriptreactgatsbyjest

The problem

Since my CSS classes are injected into the component at build time, PurgeCSS isn’t aware of them.

1const Tag = ({ name, color }) => (
2 <span className={`${color[0]} ${color[1]} inline-block rounded-lg ...`}>
3 {name}
4 </span>
5);

See how these two color classes are variables as opposed to others classes who are static?

That’s why I needed to use the whitelist configuration option. But there’s no way I would be copy pasting classes around and manually managing a whitelist.

The solution

We need to get all the TAG_COLORS values and convert them to an array of strings that the PurgeCSS whitelist option will accept.

A simple function does the trick:

1const whitelistedClasses = Object.values(TAG_COLORS).reduce(
2 (whitelistedColors, currentColors) => [
3 ...whitelistedColors,
4 ...currentColors,
5 ],
6 []
7);

Object.values(TAG_COLORS) does what its name implies and returns an array of values.

Those values are arrays themselves, so we need to reduce everything to a single array. No need to worry about duplicates, PurgeCSS is smart enough to either filter or ignore them.

All we need to do now is import whitelistedClasses into our config and the problem is solved!

I’m using the Gatsby plugin so here’s how to do it in gatsby-config.js:

1const { whitelistedClasses } = require('./src/utils/tags');
2
3module.exports = {
4 plugins: [
5 ...,
6 {
7 resolve: `gatsby-plugin-purgecss`,
8 options: {
9 tailwind: true,
10 whitelist: whitelistedClasses,
11 },
12 },
13 ],
14};

So there you go, now you don’t have to worry about copy pasting classes around every time you update a list of colors.

Of course, this is a pretty specific issue to encounter. But the idea behind this post can be applied to many situations.

Manually managing duplicate data is inefficient and can lead to buggy code if this data isn’t kept in sync. Instead, make sure that your data flows from one place to the other.


I hope this quick post was instructive. If you found it helpful, follow me on Twitter to be notified when I post the next one!

More articles from freddydumont

How to source images and data from JSON files in Gatsby

Use Gatsby's Node API to process images in JSON files with gatsby-plugin-sharp and customize the shape of your data in GraphQL nodes.

December 1st, 2019 · 4 min read

Master Git, not the command line

Learning Git isn't about memorizing commands. It's about understanding version control. I suggest using a graphical user interface (GUI…

October 12th, 2019 · 2 min read
© 2019 freddydumont
Link to $https://twitter.com/_freddydumontLink to $https://github.com/freddydumontLink to $https://www.linkedin.com/in/freddydumont/