question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[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:

  1. static style that target slots
    {
      MuiButton: {
        styleOverrides: {
          root: {
            background: 'linear-gradient(...)'
          },
          startIcon: {
            marginRight: 12,
          }
        }
      }
    }
    
  2. [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
        }
      }
    }
    
  3. [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.
              }
            })
          ]
        }
      }
    }
    
  4. [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 be
    MuiButton: {
      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 deprecate variants 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 deprecate variants at this moment)

3rd PR

  • [optional] a blog post announcement

In the end, we can close #22259, #27415 and #28107

cc @mui-org/core

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:6
  • Comments:13 (10 by maintainers)

github_iconTop GitHub Comments

4reactions
oliviertassinaricommented, Jan 24, 2022

A quick history of why there are 2 APIs

@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:

  1. Empower low-code design tools to build a design system in a Figma-like interface. This is the path that Modulz is pushing, and why they have a variant API in stitches https://stitches.dev/docs/variants
  2. Empower smarter TypeScript resolution, with no efforts: https://github.com/mui-org/material-ui/issues/19466#issuecomment-821900112
  3. It might empower static extraction, or at least caching to improve performance: https://vanilla-extract.style/documentation/recipes-api/.
  4. It might force an API on the developers to more clearly organize their styles, hopefully making it easier to maintain, when the styleOverrides is for more niche use cases of customizations.

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 be

👍

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:

  • removing a foot gun. It only works in x% of the cases and is hard to guess what each prop does. The API docs cover it a bit better, but still, it’s not as clear as using props or the ownerState.
  • reducing bundle size

variants should be deprecated.

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.

3reactions
danilo-lealcommented, Jan 4, 2022

Right, thanks for the explanation! I believe it’s a great idea to add this reasoning to the documentation when explaining the changes 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Override Box component in createTheme - Stack Overflow
You can override the Card styles globally using createTheme() because the Card has a name and a styleOverrides callback when it is styled ......
Read more >
Docs • Svelte
This page contains detailed API reference documentation. It's intended to be a resource for people who already have some familiarity with Svelte.
Read more >
(PDF) Two from Three (in XSLT) | John Lumley - Academia.edu
This paper discusses automated methods of 'downgrading' XSLT 3.0 programs into XSLT 2.0 syntax and semantics. The stimulus was running portions of a ......
Read more >
React-admin - Theming
To reuse the same style overrides in different locations across your application, create a reusable component using the MUI styled() utility. It's a...
Read more >
Light DOM Component - RFCs
As of today, all the LWC components inheriting from LightningElement render their content to the shadow DOM. This proposal introduces a new kind ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found