Skip to content

Instantly share code, notes, and snippets.

@Merott
Last active November 29, 2023 14:24
  • Star 103 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
Expose Tailwind colors as CSS custom properties (variables)

This is a simple Tailwind plugin to expose all of Tailwind's colors, including any custom ones, as custom css properties on the :root element.

There are a couple of main reasons this is helpful:

  • You can reference all of Tailwind's colors—including any custom ones you define—from handwritten CSS code.
  • You can define all of your colors within the Tailwind configuration, and access the final values programmatically, which isn't possible if you did it the other way around: referencing custom CSS variables (defined in CSS code) from your Tailwind config.

See the Tailwind Plugins for more info on plugins.

module.exports = {
  theme: {
    extend: {
      colors: {
        gray: {
          '100': '#f5f5f5',
          '200': '#eeeeee',
          '300': '#e0e0e0',
          '400': '#bdbdbd',
          '500': '#9e9e9e',
          '600': '#757575',
          '700': '#616161',
          '800': '#424242',
          '900': '#212121',
        },
      },
    },
  },
  plugins: [
    function({ addBase, theme }) {
      function extractColorVars(colorObj, colorGroup = '') {
        return Object.keys(colorObj).reduce((vars, colorKey) => {
          const value = colorObj[colorKey];

          const newVars =
            typeof value === 'string'
              ? { [`--color${colorGroup}-${colorKey}`]: value }
              : extractColorVars(value, `-${colorKey}`);

          return { ...vars, ...newVars };
        }, {});
      }

      addBase({
        ':root': extractColorVars(theme('colors')),
      });
    },
  ],
};
@emigdio821
Copy link

Is there a way to expose only the custom colors?
These ones:

extend: {
  colors: {
    customblue: '#0274b6',
    custombluehover: '#015483',
  },
},

Thanks!

@benwinding
Copy link

Thank you for this!
Side note: an AI-driven search engine led me to this solution here! 😅
Phind -> Source link

@jbasoo
Copy link

jbasoo commented May 18, 2023

I further modified @Maybach91's modification and abstracted a bit for any theme config, not just colors (theoretically, havent tested every type 😬).

Also I switched from addBase to addUtilites as my project isn't using the base styles, only utilities.

  plugins: [
    plugin(function({ addUtilities, theme }) {    
      function extractVars (obj, group = '', prefix) {
        return Object.keys(obj).reduce((vars, key) => {
          const value = obj[key];
          const cssVariable = key === "DEFAULT" ? `--${prefix}${group}` : `--${prefix}${group}-${key}`;
          
          const newVars =
          typeof value === 'string'
          ? { [cssVariable]: value }
          : extractVars(value, `-${key}`, prefix);
          
          return { ...vars, ...newVars };
        }, {});
      }
      
      addUtilities({
        ':root': {
          ...extractVars(theme('colors'), '', 'color'),
          ...extractVars(theme('boxShadow'), '', 'box-shadow')
        }
      })
    })
  ],

@y-nk
Copy link

y-nk commented Jul 10, 2023

anybody did an official plugin for that? i'm thinking should i paste this snippet or npm install

@Maybach91
Copy link

Maybach91 commented Jul 12, 2023

anybody did an official plugin for that? i'm thinking should i paste this snippet or npm install

@y-nk Yup:
https://npms.io/search?q=tailwindcss-colors-css-variables

This looks like the most maintained one

@ianhernandez
Copy link

Anyone have a typescript version of this?

@y-nk
Copy link

y-nk commented Aug 19, 2023 via email

@mathieutu
Copy link

mathieutu commented Sep 5, 2023

I works like a charm in Tailwind v3.3.3, thanks! 🎉

Here is a TS simplified version:

import { type PluginAPI } from 'tailwindcss/types/config'

export const colorVarsPlugin = ({ addBase, theme }: PluginAPI) => {
  const extractColorVars = (colorObj: Record<string, string>, colorGroup = '') => (
    Object.entries(colorObj)
      .reduce((vars, [colorKey, value]) => {
        const cssVariable = colorKey === 'DEFAULT' ? `--color${colorGroup}` : `--color${colorGroup}-${colorKey}`

        const newVars: Record<string, string> = typeof value === 'string'
          ? { [cssVariable]: value }
          : extractColorVars(value, `-${colorKey}`)

        return { ...vars, ...newVars }
      }, {})
  )

  addBase({
    ':root': extractColorVars(theme('colors')),
  })
}

EDIT: Indeed, it'd be great to find a way to purge the colors..

@joshdavenport
Copy link

joshdavenport commented Oct 18, 2023

A note to people stumbling on this gist as I did: This plugin is awesome, really nice idea, but consider adding variables to your CSS manually. Using something like the below, as long as you have access in your CSS to tailwind directives, you can reference colours and create variables from them:

:root {
  --tw-color-white: theme('colors.white');
  --tw-color-black: theme('colors.black');
  --tw-color-gray-100: theme('colors.gray.100');
  --tw-color-gray-200: theme('colors.gray.200');
  --tw-color-gray-300: theme('colors.gray.300');
  --tw-color-gray-400: theme('colors.gray.400');
  --tw-color-gray-500: theme('colors.gray.500');
  --tw-color-gray-600: theme('colors.gray.600');
  --tw-color-gray-700: theme('colors.gray.700');
  --tw-color-gray-800: theme('colors.gray.800');
  --tw-color-gray-900: theme('colors.gray.900');
  --tw-color-gray-950: theme('colors.gray.950');
}

For example, if you're using Next and following the globals.css pattern the docs describe you can add this to globals.css.

Doing it that way you don't need to worry about the bundle size reports others have mentioned (haven't looked at it myself, so no idea how badly it affects the size). Obviously the whole point of the plugin is quickly and easily provide access to all colours, but maybe you don't need that, so consider what you need contextually.

@oskarengstrom
Copy link

oskarengstrom commented Nov 29, 2023

A note to people stumbling on this gist as I did: This plugin is awesome, really nice idea, but consider adding variables to your CSS manually. Using something like the below, as long as you have access in your CSS to tailwind directives, you can reference colours and create variables from them:

@joshdavenport
This sounds great, but exactly how do you use theme() in globals.css?

@simonhamp
Copy link

@oskarengstrom if you're generating your CSS through a bundler, like Vite or Webpack, then the theme() function will be exposed to you.

It won't work in plain CSS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment