csstailwind-csstailwind-3

Tailwind - custom class combined with nested color pallet


I want to write a custom class, that would apply set of styles, but I want to be able to use it together with a color for the theme. It will probably easier to explain it by example.

So for example if we want to set background to a certain color we would add class like this:

<div class="bg-red">

And instead of background I would like to have my own custom class, that would apply new set of styles, but which I can still use together with a color:

<div class="custom-red">

So I started experimenting with Tailwind plugins and components. I wrote plugin like this:

function ({ matchComponents, theme }) {
  const getStyles = (color) => {
    return {
      position: 'relative',
      '&::before': {
        backgroundColor: color
        // ...
      }
    };
  };

  matchComponents({
    testbg: (value) => getStyles(value)
  }, {
    values: theme('colors')
  });
}

And it almost worked. I mean it is working for simple color like red. But my color pallet is more complex and nested.

theme: {
   colors: {
      primary: {
         DEFAULT: '#....'
         5: '#....'
         10: '#....'
         50: '#....'
      },
      secondary: {
         5: '#....'
         10: '#....'
      },
      red: '#....'
   }
}

And sadly it didn't generate all color possibilities. It just took the "shallow" keys of the colors and generated classes like custom-primary, custom-secondary, custom-red. But there is no custom-primary-5 for example.

So is there a straightforward way of doing it? I guess I could manually parse colors from theme and recursively go through the object and create separate component for each. But this seems like a completely weird thing to do, as the stuff I'm trying to do seems like a really basic use case for a tool like Tailwind.


Solution

  • Tailwind provides a flattenColorPalette() function that helps you flatten the object structure into a flat dictionary. This should then work with any level of color value nesting.

    const plugin = require("tailwindcss/plugin");
    const { default: flattenColorPalette } = require("tailwindcss/lib/util/flattenColorPalette");
    
    module.exports = {
      …
      plugins: [
        plugin(function ({ matchComponents, theme }) {
          const getStyles = (color) => {
            //  …
          };
    
          matchComponents({
            testbg: (value) => getStyles(value)
          }, {
            values: flattenColorPalette(theme('colors')),
          });
        }),
      ],
    }