Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CSS variables support for Material UI components #32835

Merged
merged 42 commits into from Jun 17, 2022

Conversation

siriwatknp
Copy link
Member

@siriwatknp siriwatknp commented May 20, 2022

#32868 is merged.

A part of #32049 as described in #32049 (comment)

The new tokens are added to experimental_extendTheme.js. I decided not to go with palette.grey.contrast{number} as described in the proposal because it is not practical when I tried to apply it to the components (the main problem is the Chip component).

Instead, I extract the color manipulation into the component tokens which is easier to read and customize.

Why new tokens are necessary?

We intend to ship CSS variables support as a feature in v5 (no breaking change) so when developers opt-in to this feature, they should have the SSR flashing issue fixed (that's what we will advertise). However, some components' implementation contains runtime calculations to switch values between modes, so the new tokens are needed to preserve the same behavior.

Naming

I think the token should have the shortest name possible because it makes the DevTool and usage cleaner. Also, the palette already implies that the tokens are color-related so I don't think bgColor or borderColor is necessary. Lastly, the common customization flow would start from seeing the variable from DevTool and then specify the variable in the theme, so I don't think using bg (the abbreviation of background) will cause confusion.

--mui-palette-AppBar-defaultBg
// is better than --mui-palette-AppBar-defaultBackgroundColor

Here are the new tokens:

theme.palette.AppBar.defaultBg
theme.palette.Chip.defaultBorder
theme.palette.Chip.defaultAvatarColor
theme.palette.Chip.defaultIconColor
theme.palette.FilledInput.bg
theme.palette.FilledInput.hoverBg
theme.palette.FilledInput.disabledBg
theme.palette.LinearProgress.primaryBg
theme.palette.LinearProgress.secondaryBg
theme.palette.LinearProgress.errorBg
theme.palette.LinearProgress.infoBg
theme.palette.LinearProgress.successBg
theme.palette.LinearProgress.warningBg
theme.palette.Skeleton.bg
theme.palette.Slider.primaryTrack
theme.palette.Slider.secondaryTrack
theme.palette.Slider.errorTrack
theme.palette.Slider.infoTrack
theme.palette.Slider.successTrack
theme.palette.Slider.warningTrack
theme.palette.SnackbarContent.bg
theme.palette.StepConnector.border
theme.palette.StepContent.border
theme.palette.Switch.defaultColor
theme.palette.Switch.defaultDisabledColor
theme.palette.Switch.primaryDisabledColor
theme.palette.Switch.secondaryDisabledColor
theme.palette.Switch.errorDisabledColor
theme.palette.Switch.infoDisabledColor
theme.palette.Switch.successDisabledColor
theme.palette.Switch.warningDisabledColor
theme.palette.TableCell.border
theme.palette.Tooltip.bg

The next step is to use this pattern in the existing PRs.


@siriwatknp siriwatknp added the new feature New feature or request label May 20, 2022
@mui-bot
Copy link

mui-bot commented May 20, 2022

Details of bundle changes

@material-ui/core: parsed: +1.78% , gzip: +1.05%
@material-ui/lab: parsed: +0.35% , gzip: +0.15%

Generated by 🚫 dangerJS against 44d1e3c

@siriwatknp siriwatknp changed the title Add support for CSS variables for Material UI Add CSS variables support for Material UI components May 20, 2022
Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided not to go with palette.grey.contrast{number} as described in the #32049 (comment) because it is not practical when I tried to apply it to the components (the main problem is the Chip component).

I can still see usage of contrast4 in the Chip I guess we need to update it?

packages/mui-material/src/Chip/Chip.js Outdated Show resolved Hide resolved
packages/mui-material/src/Chip/Chip.js Outdated Show resolved Hide resolved
packages/mui-material/src/Chip/Chip.js Outdated Show resolved Hide resolved
@siriwatknp
Copy link
Member Author

@mnajdova Can you take a look at the PR again?

  • Renamed some variables to make them shorter (the idea behind is in the description)
  • Use --mui as a prefix to refer to Material UI (I think --md does not make sense since we have Mui all over the places)

Copy link
Contributor

@danilo-leal danilo-leal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, excellent work, Jun! Way better to read colors like this, so refreshing!
Let me know if you need my help with anything else for this one.

Screen Shot 2022-06-15 at 02 54 41

Side note: I wish we had a different prefix other than mui but 🤷 that's life at this moment! 😅

Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One instance where TypeScript would have caught some issues :)

packages/mui-material/src/AppBar/AppBar.js Outdated Show resolved Hide resolved
},
...(!theme.vars && {
'&:-webkit-autofill': {
WebkitBoxShadow: theme.palette.mode === 'light' ? null : '0 0 0 100px #266798 inset',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe few more use-cases for the unset CSS var :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not put them in theme tokens yet. These are not directly palette tokens. There are only 2 components that contain this logic FilledInput and OutlinedInput, so I think let's wait for feedback from the community first.

packages/mui-material/src/styles/createPalette.d.ts Outdated Show resolved Hide resolved
packages/mui-material/src/styles/createPalette.d.ts Outdated Show resolved Hide resolved
@siriwatknp siriwatknp requested a review from mnajdova June 16, 2022 08:17
Comment on lines +160 to +172
...(theme.vars && {
'&:-webkit-autofill': {
borderTopLeftRadius: 'inherit',
borderTopRightRadius: 'inherit',
},
[theme.getColorSchemeSelector('dark')]: {
'&:-webkit-autofill': {
WebkitBoxShadow: '0 0 0 100px #266798 inset',
WebkitTextFillColor: '#fff',
caretColor: '#fff',
},
},
}),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mnajdova This is the logic when CSS variables exist which uses CSS selector when the mode is dark. I think we can move forward with this (it does not cause dark mode flicker) instead of creating 3 new tokens (the more tokens the bigger CSS output).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that makes sense 👍

@siriwatknp siriwatknp requested a review from vicasas June 16, 2022 12:55
@siriwatknp
Copy link
Member Author

@vicasas Would you mind taking a look if the naming makes sense to you?

@vicasas
Copy link
Member

vicasas commented Jun 16, 2022

Hi! @siriwatknp I find it incredible! What a great job with Css Vars 👏.

I have the following doubts:

  1. Regarding token names, I'm having trouble differentiating between [Component].bg and [Component].defaultBg, same for [Component].border and [Component].defaultBorder. There is a difference (apart from the color that each one contains)? just to understand

  2. Do I not see the tokens for the Alert, Avatar and SpeedDialAction components in the change or will we build them as those components are taken?

Everything else looks good (:

@siriwatknp
Copy link
Member Author

  1. Regarding token names, I'm having trouble differentiating between [Component].bg and [Component].defaultBg, same for [Component].border and [Component].defaultBorder. There is a difference (apart from the color that each one contains)? just to understand

The default refers to the background when <AppBar color="default"> . Noted that we need to document this one.

  1. Do I not see the tokens for the Alert, Avatar and SpeedDialAction components in the change or will we build them as those components are taken?

Good point. I will update those components in their PRs (which already existed) after this one is merged.

!ownerState.enableColorOnDark && {
backgroundColor: null,
color: null,
...(theme.vars && {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +108 to +114
...(ownerState.color === 'default' && {
'--AppBar-background': ownerState.enableColorOnDark
? theme.vars.palette.AppBar.defaultBg
: joinVars(theme.vars.palette.AppBar.darkBg, theme.vars.palette.AppBar.defaultBg),
'--AppBar-color': ownerState.enableColorOnDark
? theme.vars.palette.text.primary
: joinVars(theme.vars.palette.AppBar.darkColor, theme.vars.palette.text.primary),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mnajdova the case of AppBar is tricky but I managed to make it works.

To prevent dark mode flickers, we need to make sure that the stylesheet does not change between modes. That's why I have to introduce:

// component variables inside AppBar
--AppBar-background
--AppBar-color

// and use it as usual
backgroundColor: 'var(--AppBar-background)',
color: 'var(--AppBar-color)',

and then at the global theme tokens, create --mui-palette-AppBar-darkBg only for dark mode.

This will allow the AppBar to use the fallback value when it is on light mode without changing the component stylesheet.

...(ownerState.color === 'default' && {
    '--AppBar-background': ownerState.enableColorOnDark
      ? theme.vars.palette.AppBar.defaultBg
      : joinVars(theme.vars.palette.AppBar.darkBg, theme.vars.palette.AppBar.defaultBg),
      
      
// The result is
'--AppBar-background': 'var(--mui-palette-AppBar-darkBg, var(--mui-palette-AppBar-defaultBg))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is closer to what I had in mind, the only difference that I was thinking about is setting the value of unset, but not generating the CSS vars is even better 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setting the value of unset

Setting the variable to unset would not work because the variable exists so it won't use the fallback value.

// the background will be transparent
--variable-1: unset;
background-color: var(--variable-1, #fff);
// the background will be white
background-color: var(--variable-1, #fff);

Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could find one final bug, the rest looks good

Co-authored-by: Marija Najdova <mnajdova@gmail.com>
@siriwatknp siriwatknp merged commit d14be1c into mui:master Jun 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants