'How to write a Tailwind class plugin that takes a palette colour as an optional parameter
I have this style:
box-shadow: 0 0 0 100px white inset;
But I don't want white hard-coded in - I want to make a Tailwind plugin in my tailwind.config.js called bg-shadow that accepts the colour as an optional third argument, like so:
<input class="bg-shadow" /> <!-- defaults to white -->
<input class="bg-shadow-primary-500" />  <!-- specify the colour -->
Having read through the Tailwind docs on plugins, I am none the wiser as to how to achieve this!
Solution 1:[1]
You could do this with a pretty simple plugin using matchUtilities and flattenColorPalette.
In tailwind.config.js:
const plugin = require("tailwindcss/plugin");
const { default: flattenColorPalette } = require("tailwindcss/lib/util/flattenColorPalette");
module.exports = {
  ...
  plugins: [
    plugin(({ matchUtilities, theme }) => {
      matchUtilities(
        {
          "bg-shadow": (value) => ({
            boxShadow: `0 0 0 100px ${value} inset`
          })
        },
        { 
          values: flattenColorPalette(theme("colors")), 
          type: "color" 
        }
      );
    })
  ]
};
    					Solution 2:[2]
After studying this plugin (credit where credit's due) I have this now working as follows:
// tailwind.bg-shadow.plugin.js
const plugin = require("tailwindcss/plugin");
const formatShadow = (color) => `0 0 0 100px ${color} inset`;
module.exports = plugin.withOptions(
    ({className = "bg-shadow"} = {}) => {
        return ({e, addUtilities, theme, variants}) => {
            const colors = theme("colors");
            const caretColors = Object.keys(colors).reduce((acc, key) => {
                if (typeof colors[key] === "string") {
                    return {
                        ...acc,
                        [`.${className}-${e(key)}`]: {
                            "box-shadow": formatShadow(colors[key])
                        },
                    };
                }
                const colorShades = Object.keys(colors[key]);
                return {
                    ...acc,
                    ...colorShades.reduce(
                        (a, shade) => ({
                            ...a,
                            [`.${className}-${e(key)}-${shade}`]: {
                                "box-shadow": formatShadow(colors[key][shade])
                            },
                        }),
                        {}
                    ),
                };
            }, {});
            addUtilities(caretColors, variants("bg-shadowColor"));
        };
    },
    () => ({
        variants: {caretColor: ["dark", "active"]},
    })
);
And usage in tailwind.config.js:
module.exports = {
    ...
    plugins: [
        require('./tailwind.bg-shadow.plugin')
    ],
}
    					Solution 3:[3]
There are a few ways for you to extend box shadow.
Easier without a plugin, just configuration
Demo: https://play.tailwindcss.com/2mrdK51h8U?file=config
boxShadow property exists for you to extend.
module.exports = {
  theme: {
    extend: {
      boxShadow: '0 0 0 100px white inset',
      colors: {
        'primary-500': '5px 5px 15px 5px rgba(0,0,0,0.42)',
      }
      // Or do it in one shot
      // boxShadow: {
      //   DEFAULT: '0 0 0 100px white inset;',
      //   'primary-500': '5px 5px 15px 5px rgba(0,0,0,0.42)',
      // },
    },
  },
  plugins: [],
}
You can either extend boxShadow and colors separately or do it in one shot as shown above.
The downside is that, you need to use shadow-* prefix.
So let's check out the next option, using a plugin.
Using a plugin
Demo: https://play.tailwindcss.com/hJaWBntnq0?file=config
You can create a plugin that lets you or users to provide shadow colors.
matchUtilities lets you provide dynamic values (similar to addUtilities) using custom colors.
The second arg for theme(themeName, defaultThemeValue) is a default configuration you can provide in case users didn't provided their own.
const plugin = require('tailwindcss/plugin')
// This is in-case a user didn't extend `bgShadowColors`.
const defaultBgShadowColors = {
  DEFAULT: '0 0 0 100px red inset',
  'primary-100': '5px 5px 15px 5px rgba(0,0,0,0.12)',
  'primary-200': '5px 5px 15px 5px rgba(0,0,0,0.20)',
  'primary-300': '5px 5px 15px 5px rgba(0,0,0,0.22)',
  'primary-400': '5px 5px 15px 5px rgba(0,0,0,0.32)',
  'primary-500': '5px 5px 15px 5px rgba(0,0,0,0.42)',
  'primary-600': '5px 5px 15px 5px rgba(0,0,0,0.62)',
  'primary-700': '5px 5px 15px 5px rgba(0,0,0,0.82)',
}
const bgShadowPlugin = plugin(function ({ matchUtilities, theme }) {
  // Refer to https://tailwindcss.com/docs/plugins#dynamic-utilities
  matchUtilities(
    {
      'bg-shadow': (value) => ({
        'box-shadow': value,
      }),
    },
    // If user hasn't extended `bgShadowColors`, then use `defaultBgShadowColors`
    { values: theme('bgShadowColors', defaultBgShadowColors) }
  )
})
module.exports = {
  theme: {
    extend: {
      bgShadowColors: {
        DEFAULT: '0 0 0 100px red inset',
        'primary-100': '5px 5px 15px 5px rgba(0,0,0,0.12)',
        'primary-200': '5px 5px 15px 5px rgba(0,0,0,0.20)',
        'primary-300': '5px 5px 15px 5px rgba(0,0,0,0.22)',
        'primary-400': '5px 5px 15px 5px rgba(0,0,0,0.32)',
        'primary-500': '5px 5px 15px 5px rgba(0,0,0,0.42)',
        'primary-600': '5px 5px 15px 5px rgba(0,0,0,0.62)',
        'primary-700': '5px 5px 15px 5px rgba(0,0,0,0.82)',
      },
    },
  },
  plugins: [bgShadowPlugin],
}
    					Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | Chris Koelle | 
| Solution 2 | joshcomley | 
| Solution 3 | dance2die | 
