tailwindcss: variable colors with not working with theme function on plugins

I’m trying to create a plugin for Tailwind 3.1.8, but when I use variables on colors with the new syntax - rgb(var(--primary) / <alpha-value>) - the color stop working.

I created an example on https://play.tailwindcss.com/2apCJBfHdC

Removing the / <alpha-value> from the color value make things work again.

I’m doing something wrong?

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 42
  • Comments: 38 (8 by maintainers)

Most upvoted comments

interestingly, theme(), "theme()" and @apply will all generate different values:

see https://play.tailwindcss.com/fX0CEoXvGu

addUtilities({
  '.test': {
    color: theme('colors.primary.DEFAULT'),
    background: 'theme("colors.primary.DEFAULT")',
    '@apply border-primary': '',
  },
})

will generate:

.test {
    color: rgb(var(--primary) / <alpha-value>);
    background: rgb(var(--primary) / 1);
    --tw-border-opacity: 1;
    border-color: rgb(var(--primary) / var(--tw-border-opacity));
}

looks like only @apply does the correct thing currently?

After little more investigation was very clear how to make it work.

First you need to declare your color variable using RGB and not HEX

On your css config:

$blue: 56, 114, 221;

@layer base {
    :root {
        --my-color-blue: #{$blue};
    }
}

On tailwind config

module.exports = {
    theme: {
        extend: {
            colors: {
                'my-color-blue': 'rgb(var(--my-color-blue), <alpha-value>)',
            },
        },
    },
    plugins: [],
};

Usage:

<div class="bg-my-color-blue bg-opacity-20">
    Bingo!
</div>

Hey folks! Looking at this issue today which has been open for quite a while and thought I would share what’s possible today with Tailwind CSS v3.x and also what we’re hoping to support in the upcoming v4.0 release.

Reading through this issue it appears there are two different things being discussed: 1) how to add color opacity modifier support when authoring plugins, and 2) how to define colors using CSS variables while still being able to use the color opacity modifier. I will address these separately below:

Writing plugins

The original reason this issue was open was because @gsmeira was trying to write a Tailwind plugin that could have a color opacity modifier. As @thecrypticace mentioned (https://github.com/tailwindlabs/tailwindcss/issues/9143#issuecomment-1285697099), this is not possible using the addUtilities function. However, you can do this using the matchUtilities function, like this:

let plugin = require('tailwindcss/plugin')

plugin(function ({ matchUtilities }) {
  matchUtilities(
    {
      foo: (value) => ({ color: value }),
    },
    {
      type: ['color'],
      values: {
        red: '#ff0000',
        green: '#00ff00',
        blue: '#0000ff',
      },
    }
  )
})

The only limitation with this approach is that you cannot create a root-level utility that supports the color opacity modifier — something like foo/50. This is unlikely to change in Tailwind CSS v3.x, however we’re busy working on v4.0 and hope to support this in that version.

Using CSS variables

In addition to writing plugins, it appears that a bunch of people in this thread are also struggling with how to use the color opacity modifier when they are defining their colors using CSS variables. Something like this:

// tailwind.config.js
export default {
  theme: {
    extend: {
      colors: {
        primary: 'var(--my-primary-color)'
      }
    },
  },
  plugins: [],
}

While this works as a simple color utility (eg. text-primary), it doesn’t work when you try to use the color opacity modifier (eg. text-primary/50).

Our documentation does explain how to do this (see here), however this assumes that you’re using rgb colors. If you’re using hex, oklch, or other color formats you need to get a little more creative with how you implement this.

Let’s say you have the following CSS variables defined in your project:

html {
  --my-hex-color: #ff0000;
  --my-oklch-color: oklch(63.24% 0.286 29);
  --my-named-color: red;
}

Here is how you can use the color-mix() function in CSS to make all of these colors work in Tailwind with the color opacity modifier:

// tailwind.config.js
export default {
  theme: {
    extend: {
      colors: {
        hex: 'color-mix(in srgb, var(--my-hex-color) calc(<alpha-value> * 100%), transparent)',
        oklch: 'color-mix(in srgb, var(--my-oklch-color) calc(<alpha-value> * 100%), transparent)',
        named: 'color-mix(in srgb, var(--my-named-color) calc(<alpha-value> * 100%), transparent)',
      }
    },
  },
  plugins: [],
}

With that all in place you can now use text-hex, text-hex/50, text-oklch, text-oklch/50, text-named, text-named/50, etc.

Here is a Tailwind Play demoing this: https://play.tailwindcss.com/LJMZg2LLta


Really hope that helps! Going to close this issue for now as there are workarounds available in the current version of Tailwind, and it’s something we plan to change in v4.0 🤙

The docs for HSL are incorrect

  // Using modern `hsl`
      primary: 'hsl(var(--color-primary) / <alpha-value>)',
      secondary: 'hsl(var(--color-secondary) / <alpha-value>)',

should be

  // Using modern `hsl`
      primary: 'hsl(var(--color-primary), <alpha-value>)',
      secondary: 'hsl(var(--color-secondary), <alpha-value>)',

This works for me. It was covered in the opacity section of this video https://www.youtube.com/watch?v=MAtaT8BZEAo

It seems like the docs don’t mention this anywhere?

https://play.tailwindcss.com/oYulJ30B14?file=config

No worries! Sorry for the late reply. We have been thinking this through some but other things took priority for the v3.2 release.

The reason it doesn’t work for plugins like this is two fold:

  1. addUtilities doesn’t do anything fancy like parsing data types. It’s basically to put pure CSS into the stylesheet whenever a utility is used (and it can handle variants ofc)
  2. matchUtilities does parse data types and it takes a type option that lists all acceptable “types” for a plugin — as well as a list of values. You get the <alpha-value> behavior for “free” when using it and your type list includes color.

For example, this works today: https://play.tailwindcss.com/1a6LIjNR2S?file=config — Except for the DEFAULT case + opacity modifier which I believe is a bug but I’ll have to check on that. However, we’re also thinking through what we want to work here.

I think that in an ideal world each plugin would take in the opacity and modify the color itself (or we provide a function to do this for you — not sure though). And we could remove this special case for the color type. We’re going to try to dedicate some time soon-ish to figuring out how this should work at a high level for plugin authors to see if:

  1. The existing matchUtilities API / workaround is what we want; OR
  2. If there’s a better, more automatic API that we can design and implement.

Looks like a PR was opened about this in the past but somehow the behaviour isn’t working anymore. https://github.com/tailwindlabs/tailwindcss/pull/8652

~Related, it would be nice to be able to overwrite the <alpha-value> when using theme(), which I don’t believe is possible currently.~ Looks like that is possible. https://github.com/tailwindlabs/tailwindcss/pull/9008

You can use hex or any color format you want if you use color-mix.

colors: {
  primary: `color-mix(
    in srgb,
    var(--primary-color-in-hex),
    transparent calc(100% - 100% * <alpha-value>)
  )`
}

You can make it much less wordy with a simple function like:

const colorMixAlphaValueWithCustomProperty = customPropertyName => `color-mix(
  in srgb,
  var(${customPropertyName}),
  transparent calc(100% - 100% * <alpha-value>)
)`

/*
colors: {
  primary: colorMixAlphaValueWithCustomProperty('--primary-color-in-hex')
  secondary: colorMixAlphaValueWithCustomProperty('--secondary-color-in-hex')
}
*/

A sample play: https://play.tailwindcss.com/PLN66o7PtF?file=config

@Pagebakers that is incorrect. The example is using the correct “modern” CSS syntax.

See example here: https://play.tailwindcss.com/rFbKXTknA2 And the CSS spec: https://www.w3.org/TR/css-color-4/#the-hsl-notation

Something that might be valuable. I’ve found that theme('colors.primary.DEFAULT / 1') still works when configuring Tailwind Typography variables, but not JS based custom plugin configurations. If anyone found a workaround I’d love to learn.

var(--my-color-black) / <alpha-value>

Just wanted to comment also experiencing the same problem as re2005 extending the theme alpha-value is not being parsed properly.

As the docs suggest it should work in the CSS variables section https://tailwindcss.com/docs/customizing-colors#using-css-variables

Same issue here.

Extending the theme colors won’t work.

module.exports = {
    darkMode: 'class',
    content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
    theme: {
        extend: {
            colors: {
                'my-blue': 'rgb(var(--my-color-black) / <alpha-value>)',
            },
        },
    },
    plugins: [],
};

:root, [data-theme=“default”] { // main –color-primary-darker: hsl(220, 90%, 36%); –color-primary-dark: hsl(220, 90%, 46%); –color-primary: hsl(220, 90%, 56%); –color-primary-light: hsl(220, 90%, 66%); –color-primary-lighter: hsl(220, 90%, 76%); –color-primary-a20: hsla(220, 90%, 56%, 0.2);

–color-accent-darker: hsl(355, 90%, 41%); –color-accent-dark: hsl(355, 90%, 51%); –color-accent: hsl(355, 90%, 61%); –color-accent-light: hsl(355, 90%, 71%); –color-accent-lighter: hsl(355, 90%, 81%);

// color contrast –color-bg: hsl(0, 0%, 100%); –color-bg-a00: hsla(0, 0%, 100%, 0); –color-contrast-lower: hsl(0, 0%, 95%); –color-contrast-low: hsl(240, 1%, 83%); –color-contrast-medium: hsl(240, 1%, 48%); –color-contrast-high: hsl(240, 4%, 20%); –color-contrast-higher: hsl(240, 8%, 12%); –color-contrast-higher-a90: hsla(240, 8%, 12%, 0.9);

// semantic –color-border: var(–color-contrast-low); GTA Portal

@thecrypticace @crswll color-mix() seems to be supported in all major browsers. It’s now completely safe to update the docs to include this.

In fact, this project of mine successfully uses this approach.

@crswll thank you very much, but I just realized it was even simpler and decided to open up a PR for a doc example:

// tailwind.config.js
module.exports = {
  theme: {
    colors: {
      // For --color-primary: #ff73b3
      primary: 'rgb(from var(--color-primary) r g b / <alpha-value>)',
    }
  }
}
colors: {
  primary: 'rgb(var(--color-primary) / <alpha-value>)',
}

So using "theme('colors.primary')" instead of theme('colors.primary') seems to do the trick. Nice 👍

this issue has been open for more than half and a year now. when will this issue be fixed?

Hey @austinm911 thanks for the example, the problem is that we are trying to set alpha on custom colors.