[RFC] Consolidate component theming into a one API (aka `styleOverrides`)
See original GitHub issue~As discussed in https://github.com/mui-org/material-ui/issues/28107#issuecomment-997368895, there are 2 current APIs that provide component theming.~
~- styleOverrides
~
~- variants
~
~A quick history of why there are 2 APIs: In v4, styleOverrides
is not able to support dynamic props via callback due to the limitation of JSS. That’s when we introduce another API (variants
) to inject a specified style when a set of props is matched. However, it causes some confusion with the component variant
prop (ex. #29455) and exposes new syntax but has limitations because it cannot create matching props like this (variant === 'filled' && color !== 'success'
).~
~If we step back, we will see that both of the APIs are trying to provide the same thing, component theming. Fortunately, in MUI v5, the styleOverrides
supports callback thanks to emotion & styled-components so it is worth to drop variants
and expose only one theming API.~
For history, @oliviertassinari explain in https://github.com/mui/material-ui/issues/30412#issuecomment-1018467855
Here are all the requirements that styleOverrides
can/should support:
- static style that target slots
{ MuiButton: { styleOverrides: { root: { background: 'linear-gradient(...)' }, startIcon: { marginRight: 12, } } } }
- [new] dynamic style from props (in v4, we provide
classes
that can be used to target each prop){ MuiButton: { styleOverrides: { // colorPrimary: { ... }, in v4 we do this // which can be translated into root: (props) => ({ ...props.color === 'primary' && { ... } }), // other slots can be function as well } } }
- [new] support array syntax for using a lot of pseudo-class (or nested class), so that it does not override each other. (this is an existing feature that emotion & styled-components are already supported)
{ MuiButton: { styleOverrides: { // root: props => ({ // '&:after: { display: 'block', color: 'red' }, // ...props.color === 'primary' && { // '&:after: { color: 'blue' }, // this `display` in the upper :after is gone because this is object. // } // }), root: [ { '&:after: { display: 'block', color: 'red' } }, props => ({ ...props.color === 'primary' && { '&:after: { color: 'blue' }, // this `display` in the upper :after is still there. } }) ] } } }
- [new] it can be used with the new
experimental_sx
utility!{ MuiButton: { styleOverrides: { root: sx({ p: 2, bgcolor: 'primary.main', }), } } }
Deprecation
styleOverrides
should contain only slot keys and deprecate all classes because those can be done by using callback. eg: for Button, the styleOverrides should beMuiButton: { styleOverrides: { root: {}, startIcon: {}, endIcon: {}, // outlinedPrimary, outlinedSecondary, ..., sizeSmall, sizeLarge, ...etc. should be deprecated but still work in v5 } }
- ~
variants
should be deprecated.~ (We don’t plan to deprecatevariants
at this moment)
Plan
I think it is possible to aim for NO breaking change, but some deprecations are expected. We can try to create codemod that helps migrate the deprecation.
✅ 1st PR https://github.com/mui-org/material-ui/pull/30524
- make
styleOverrides
support callback (only for slot keys) - ~deprecate
variants
themeing feature~ reverted - update docs about the callback support
2nd PR
- deprecate non-slot class keys (only in theming styleOverrides)
- create codemod for
- migrate classes format in
styleOverrides
to callback - ~migrate
variants
to styleOverrides callback~ (We don’t plan to deprecatevariants
at this moment)
- migrate classes format in
✅ 3rd PR
- [optional] a blog post announcement
Issue Analytics
- State:
- Created 2 years ago
- Reactions:6
- Comments:13 (10 by maintainers)
Top GitHub Comments
@siriwatknp From my perspective, this is not the reality of what happened. It was not about JSS. The introduction of the variant API: #15573, #21749. But I also realize that these issues don’t cover the point I’m going to detail: static definition. #21648 might be the most insightful on the history, with the different options that we considered.
From my perspective, the key selling point of the variant API is that the resolution is static. In practice, the variant API allows:
styleOverrides
is for more niche use cases of customizations.👍
I think that it could be an issue on its own as we already talked about doing it somewhere, explaining in detail the pain and the gain. I believe the why is about:
ownerState
.It’s not obvious to me that it should be. One option could be to frame styleOverrides and variants for two distinct use cases, encouraging the latter, and using the former as an escape hatch.
Right, thanks for the explanation! I believe it’s a great idea to add this reasoning to the documentation when explaining the changes 😃