Skip to content

Support CSS variables as theme option #12827

@abhisheksarka

Description

@abhisheksarka

Supporting CSS variables would:

Benchmark

Activity

oliviertassinari

oliviertassinari commented on Sep 10, 2018

@oliviertassinari
Member

@abhisheksarka Supporting this would probably mean we support theme colors as CSS variables use case. I have nothing against supporting it, quite the opposite! The limitation right now is that we are performing color manipulation in JavaScript. I'm not sure there is any quick away around this problem. cc @mbrookes.

changed the title [-]Support for gradient directly in theme configurations[/-] [+]Support CSS variables as theme option[/+] on Sep 24, 2018
rlacorne

rlacorne commented on Mar 17, 2019

@rlacorne

It is actually very easy to provide javascript dynamism to CSS variables. And in a way that stays sort of semantic.

Say you have a color value graded on an hsla rotation, and that the dynamic part is the H parameter.

The static css would be written as such : color: hsla(var(--graded-value), 100, 100, 1);

Now of course javascript cannot go write that in CSS (It can, but it would remove the whole purpose of variables).

What you CAN do is use the inheritance hierarchy of the cascade.

So therefore, something like <p style="--graded-value: 92">text</p> will actually affect the value read by the CSS variable.

And javascript, especially in react, has no problem changing the value of inline styles. It is still an external declaration, as the computed use of the variable value stays in the CSS, but declared by the component as a style configuration, not a declaration.

It is often seen as wrong to declare inline styles, but in this case I see it more as a data-attribute use. This can save huge amounts of CSS, and allow a single style declaration to produce multiple results.

I have been using this method for a while to produce content with graded, dynamic values, and it is buttery smooth, as the DOM has the final word on its visual configuration, CSS just reads and apply it.

There is a caveat with dynamically rendered components not respecting the CSS variables cascade, but there are workarounds around it.

mbrookes

mbrookes commented on Mar 18, 2019

@mbrookes
Member

@rlacorne The original request was to somehow support this as a theme option. Inline styles are a different beast.

@oliviertassinari apologies I missed the original name-check. I have no idea how we could reconcile those two concerns.

rlacorne

rlacorne commented on Mar 18, 2019

@rlacorne

It can absolutely be used for themes in the same way.

CSS has the :root {} decalaration, it's only a matter of injecting global css variables on the app css :root.

$my-color: #bada55;

:root { --my-color: #bada55 }, only the variable version is much more stronger in its use and tweakability for redefinitions.

a-x-

a-x- commented on Jul 26, 2019

@a-x-
Contributor

We have scripts, that passing all the mui theme consts to css variables on app init

and we use them like this:

.foo {
  padding: calc(var(--spacing-unit) * 2px);
  transition: padding calc(var(--transitions-duration-shortest) * 1ms);
}

it's great!

one problem with some theme-functions. but we have no cases for them for now


Screenshot 2019-07-26 at 14 52 30

our current css variable provider looks like
export function asCssConsts (theme, path) {
  const themeConsts = require('./get-set').get(theme, path);

  return Object.entries(themeConsts).reduce((res, [key, val]) => {
    return Object.assign(res, { ['--' + `${ path }.${ key }`.replace(/\./g, '-')]: val });
  }, {});
}

const styles = (theme) => ({
  '@global :root': {
    '--app-background-color': '#f4f4f4',

    ...asCssConsts(theme, 'spacing'), // e.g. --spacing-unit
    ...asCssConsts(theme, 'transitions.duration'), // e.g. --transitions-duration-shortest
    ...asCssConsts(theme, 'transitions.easing'), // e.g. --transitions-easing-easeInOut
    ...asCssConsts(theme, 'shape'), // e.g. --transitions-shape-borderRadius
    ...asCssConsts(theme, 'zIndex'), // e.g. --zIndex-tooltip
// ...
a-x-

a-x- commented on Jul 26, 2019

@a-x-
Contributor

But It's harder to pass the theme.typography and pallete rule-sets. Css variables connot solve this. So we're use jss with ThemeProvider for that cases

a-x-

a-x- commented on Jul 26, 2019

@a-x-
Contributor

some css processors allow extending (css-modules we use doesn't support it good :( out of the box)

so some mui plugin can expose rule-sets for extending like:

.typography-body1 {
  color: var(--theme-typography-body1--color);
  font-family: var(--theme-typography-body1--fontFamily);
  /* ... */
}

might be it can be useful with some post-css plugin, that enables extending

.myText {
  extends: .typography-body1;
  color: red;
}
a-x-

a-x- commented on Jul 26, 2019

@a-x-
Contributor

for one #12827 (comment) above

ok, mui@4 as I see already does something like I propose with extendable rule-sets.

But we don't want to use global selectors by default and we're gonna disable this new behaviour,
so it'll be good, if even w/o global selector we can use extendable rule-sets

mh-alahdadian

mh-alahdadian commented on Nov 28, 2019

@mh-alahdadian

hey guys
I had always using css variables in all my codes and for material components I always need to override colors which component setted them from theme (that is because I didn't wants to set theme and styles in my js files and I wants to do taht in my css files)
now I had do something to use css variables in material-theme like this
palette: { primary: { main: "rgba(var(--primary-color-tuple))", }, secondary: { main: "rgba(var(--secondary-color-tuple))", }, }
and I can override these two css variable where ever I want
but it would be great that you wouldn't check my string up there and then I could use `main: "var(--primary-color)" instead of using rgba function and it would be more better becoause of performance and that in this mode I could use any css color type (such as named or hex) that I want in my css variable instead of having a tuple of numbers

so is there any plan to let us using css variables easily?

sorry for bad english

51 remaining items

siriwatknp

siriwatknp commented on Oct 26, 2022

@siriwatknp
Member

Hey everyone, we have the experimental APIs to generate the theme tokens to CSS variables. Please have a look at https://mui.com/material-ui/experimental-api/css-theme-variables/overview/.

I'm closing this issue!

Falven

Falven commented on Mar 26, 2023

@Falven

@siriwatknp Any reason this functionality doesn't generate the spacing, transition, etc. variables?

siriwatknp

siriwatknp commented on Mar 27, 2023

@siriwatknp
Member

@siriwatknp Any reason this functionality doesn't generate the spacing, transition, etc. variables?

That'd be the next improvements.

Falven

Falven commented on Mar 27, 2023

@Falven

@siriwatknp thanks. I found the shouldSkipGeneratingVar function and override it to get some more properties generated. One problem I found is that if you're trying to override the primary and secondary colors from the variables with your own colors the elements will flash with the default color before applying yours.

siriwatknp

siriwatknp commented on Mar 27, 2023

@siriwatknp
Member

@siriwatknp thanks. I found the shouldSkipGeneratingVar function and override it to get some more properties generated. One problem I found is that if you're trying to override the primary and secondary colors from the variables with your own colors the elements will flash with the default color before applying yours.

Please create a new issue and provide a CodeSandbox, I can take a look at it.

peterhirn

peterhirn commented on Oct 11, 2023

@peterhirn

Setting primary/secondary palette colors via var(--xyz) still doesn't work and there is no mention of overriding these colors in the official documentation.

Using getComputedStyle to set the colors seems to work, but then requires more code to honor dark/light mode toggle.

Anyone got a good solution for this? 🙏

ps. telling users that the html will be larger and therefore the FCP slower is moot when everyone is using brotli/gzip anyways and the size difference is very likely insignificant.

siriwatknp

siriwatknp commented on Oct 12, 2023

@siriwatknp
Member

var(--xyz)

Can you create a new issue and give some more detail about it? thanks a lot.

peterhirn

peterhirn commented on Oct 12, 2023

@peterhirn

Following these instructions https://mui.com/material-ui/experimental-api/css-theme-variables/customization/#color-schemes

  const theme = extendTheme({
    colorSchemes: {
      light: {
        palette: {
          primary: {
            main: "var(--my-color)"
          }
        }
      },
      dark: {
        palette: {
          primary: {
            main: "var(--my-color)"
          }
        }
      }
    }
  })

produces the following error

MUI: Unsupported `var(--my-color)` color.
The following formats are supported: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().

Wrapping the values in rgb or rgba doesn't seem to work, whereas using a hex literal like #ff0000 works.

DGaibor

DGaibor commented on Feb 7, 2024

@DGaibor

Following these instructions https://mui.com/material-ui/experimental-api/css-theme-variables/customization/#color-schemes

  const theme = extendTheme({
    colorSchemes: {
      light: {
        palette: {
          primary: {
            main: "var(--my-color)"
          }
        }
      },
      dark: {
        palette: {
          primary: {
            main: "var(--my-color)"
          }
        }
      }
    }
  })

produces the following error

MUI: Unsupported `var(--my-color)` color.
The following formats are supported: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().

Wrapping the values in rgb or rgba doesn't seem to work, whereas using a hex literal like #ff0000 works.

I have the same issue.
I have this:

palette:{
        primary: {
            light: 'var(--foreground-first-light)',
            main: 'var(--foreground-first)',
            dark: 'var(--foreground-first-dark)',
            contrastText: 'var(--foreground-first-contrastText)',
        },
}

and when I use I get an error

Unhandled Runtime Error
Error: MUI: Unsupported `var(--foreground-first)` color.
The following formats are supported: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
siriwatknp

siriwatknp commented on Aug 6, 2024

@siriwatknp
Member

@DGaibor Referencing to other CSS variables is not yet supporting because the primary.main is used to generate other tokens, so it has to be the format in the error.

unhaten

unhaten commented on Sep 17, 2024

@unhaten

@DGaibor Referencing to other CSS variables is not yet supporting because the primary.main is used to generate other tokens, so it has to be the format in the error.

if i can't use vars in my ThemeProvider config in order not to set the same var that i have in hexcode for my every button - what is the point of all this and does this problem has any workaround?

I mean a MUST use hex-code only that I have, and I can't just put my var into rgb(), it just does not make sense

oliviertassinari

oliviertassinari commented on Sep 17, 2024

@oliviertassinari
Member

@unhaten it sounds like you are looking for a different issue #37901.

This one is about using CSS variables for components styles and not hard coded values over and over again.

cbn-falias

cbn-falias commented on Feb 17, 2025

@cbn-falias

Got it working quite well but there might be still hidden issues or things could break with future updates:

:root {
  --my-color: 255 0 0;
  --my-text: 0 255 0;
}
...
palette: {
  primary: {
    main: "rgb(var(--my-color))"
  },
  text: {
    primary: 'rgb(var(--my-text))',
    primaryChannel: 'var(--my-text)',
  }
}
...

More details

We also use TailwindCSS in our project, so I got the main idea from here: Tailwind Docs - Using CSS variables

Unfortunately MUI has some very specific color conversions where this approach doesn't always work.
Although there are no errors or warnings there can be some "hidden issues" which can be identified when searching for NaN in the Styles of the DevTools.
Image

Workaround 1: Channel properties

In some cases it's possible to specifically set the Channel property.

text: {
  primary: 'rgb(var(--neutral-100-color))',
  primaryChannel: 'var(--neutral-100-color)',
}

Workaround 2: Specific components

Some colors of MUI components are calculated in code, so they basically can't work with CSS variables if the aren't computed.
See createThemeWithVars.js.
My best solution right now is to directly set them in the theme:

palette: {
  LinearProgress: {
    errorBg: 'rgb(var(--error-main-color))',
    // with `color-mix` it's possible to apply the same as MUI does in code
    primaryBg: 'color-mix(in srgb, rgb(var(--my-color)) 38%, white)',
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

breaking changeIntroduces changes that are not backward compatible.priority: importantThis change can make a difference.scope: systemSpecific to @mui/system.type: new featureExpand the scope of the product to solve a new problem.

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @mbrookes@Falven@not-only-code@httpete@peterhirn

      Issue actions

        Support CSS variables as theme option · Issue #12827 · mui/material-ui