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

[RFC] Extend variants to support slots #28107

Closed
mnajdova opened this issue Sep 2, 2021 · 12 comments
Closed

[RFC] Extend variants to support slots #28107

mnajdova opened this issue Sep 2, 2021 · 12 comments
Assignees
Labels
discussion package: system Specific to @mui/system RFC Request For Comments

Comments

@mnajdova
Copy link
Member

mnajdova commented Sep 2, 2021

This RFC is no longer needed because theme.styleOverrides supports already support variants in v6.

The problem

In the theme we already have an API for adding custom style overrides for some combination of props. For example:

const theme = createTheme({
  components: {
    MuiButton: {
      variants: [
        {
          props: { variant: 'dashed' },
          style: {
            textTransform: 'none',
            border: `2px dashed grey${blue[500]}`,
          },
        },
        {
          props: { variant: 'dashed', color: 'secondary' },
          style: {
            border: `4px dashed ${red[500]}`,
          },
        },
      ],
    },
  },
});

However, with the current setup, developers can only add variants for the root component. If they need to add overrides on some of the slots inside, they need to use class selectors, hence increase the specificity. For example:

const theme = createTheme({
  components: {
    MuiButton: {
      variants: [
        {
          props: { variant: 'dashed' },
          style: {
            textTransform: 'none',
            border: `2px dashed grey${blue[500]}`,
+           '& .MuiButton-startIcon': {
+             textDecoration: 'underline',
+           },
          },
        },
        {
          props: { variant: 'dashed', color: 'secondary' },
          slot: 'Content',
          style: {
            border: `4px dashed ${red[500]}`,
          },
        },
      ],
    },
  },
});

The solution

In order to fix this, this RFC proposes we add a new additional property for each variant, call slot, that would indicate where these style overrides need to be applied. For example:

const theme = createTheme({
  components: {
    MuiButton: {
      variants: [
        {
          props: { variant: 'dashed' },
          style: {
            textTransform: 'none',
            border: `2px dashed grey${blue[500]}`,
-           '& .MuiButton-startIcon': {
-             textDecoration: 'underline',
-           },
          },
        },
+      {
+        props: { variant: 'dashed' },
+        slot: 'Content',
+        style: {
+          textDecoration: 'underline',
+        },
+      },
        {
          props: { variant: 'dashed', color: 'secondary' },
          slot: 'StartIcon',
          style: {
            border: `4px dashed ${red[500]}`,
          },
        },
      ],
    },
  },
});

When we create the slot components, we already have the slots set, for example, this is the start icon slot of the Button component.

const ButtonStartIcon = styled('span', {
  name: 'MuiButton',
  slot: 'StartIcon',
  overridesResolver: (props, styles) => {
    const { ownerState } = props;

    return [styles.startIcon, styles[`iconSize${capitalize(ownerState.size)}`]];
  },
})({/* the styles of the component*/});

The change is not a breaking change and can be added at any moment. We can treat non setting slot as a Root as we did till now.

Prio-arts

@mnajdova mnajdova added status: waiting for maintainer These issues haven't been looked at yet by a maintainer discussion package: system Specific to @mui/system and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Sep 2, 2021
@mnajdova mnajdova self-assigned this Sep 2, 2021
@oliviertassinari
Copy link
Member

I think that it would be great to expand on the pain. For instance, maybe nested selectors in the theme is OK in most cases. I would also be curious to see the prior arts in the space.

@mnajdova
Copy link
Member Author

mnajdova commented Sep 2, 2021

I think that it would be great to expand on the pain. For instance, maybe nested selectors in the theme is OK in most cases

I started thinking about this as I saw complain that the styles overrides are not type safe (as both styled and the sx prop do not accept slots). My thinking was that we can at least make the theme variants type safe, so I wrote this idea in the RFC before I will move on something else and forget about it 😃

We can wait to see if this will resonate with the community and whether it is actually a pain worth solving.

@mnajdova
Copy link
Member Author

@siriwatknp FYI

@siriwatknp
Copy link
Member

siriwatknp commented Nov 12, 2021

I think we should close this RFC, #27415, and open a new RFC to discuss about which API we want to go with.

@mnajdova Is it sounds good?

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 12, 2021

to discuss about which API we want to go with.

Starting with the pain :). What's the problem? Why is it worth a breaking change or if it's not breaking an API fragmentation?

@siriwatknp
Copy link
Member

siriwatknp commented Nov 15, 2021

to discuss about which API we want to go with.

Starting with the pain :). What's the problem? Why is it worth a breaking change or if it's not breaking an API fragmentation?

My purpose is to have one place to discuss which way we want to go (stylesOverrides and variants are doing the same thing, we should have only 1 API) because there are several places at this point.

I don't think this will cause a breaking change but deprecation is expected.

@mnajdova
Copy link
Member Author

I propose we close #27415 see #27415 (comment) and then this will be one place where we can discuss this. I don't think opening third issue will help.

@siriwatknp
Copy link
Member

siriwatknp commented Dec 19, 2021

Goal

Decide on one API between styleOverrides and variant for dynamic theming. Both of them (at the end) are trying to solve the same thing which is theming capabilities. I think the reason why we have both of them at this point is that of some limitation in v4. But now, with emotion or styled-components, it is possible to use only 1 API. It is a matter of what the API should look like.

Requirements

Let's make sure that we have considered all possible use cases about theme customization so that we can pick the API that provides the best experience.

  1. target root element: eg. "I want to change the size of the default button"
  2. target slot element: eg. "I want to reduce the size of the icon inside of every button sizes"
  3. target specific props: eg "I want to force the aspect-ratio of the CardMedia for component: img"
    • should consider the prop that is an object eg. anchorOrigin
    • should consider a combination of props, and/or negate props. eg. variant: filled & color is not success
  4. sx syntax: "Can I use sx style in the theme"?

API

styleOverrides option

the existing approach already supports (1) (2, partially) but NOT (3-6). To make styleOverrides support 3-6, the callback must be added, which looks something like this:

{
  components: {
    MuiCardMedia: {
      styleOverrides: {
        root: (props) => ({
          ...component === 'img' && {
            aspectRatio: '16 / 9',
          },
        }),
      }
    },
    MuiButton: {
      styleOverrides: {
        root: props => ({
          ...props.variant === 'filled' && props.color !== 'success' && {
            // styles
          }
        }),
        // with callback, the `classKeys` is not needed anymore and can be reduced to only slots.
      }
    },
    MuiBadge: {
      styleOverrides: {
        root: sx({
          px: 2,
          py: 1,
        })
      }
    }
  }
}

Most CSS API can be deprecated, only slots are needed to support requirement (2).

Custom variants option

  • (1): ✅
  • (2): need to add kind to support slot overrides as proposed in this issue
  • (3): I don't see a nice way how to make it works with negating props eg. (variant === 'filled' && color !== 'success')
  • (4): ✅
    {
      components: {
        MuiBadge: {
          variants: [
            {
              props: { color: 'success' },
              style: sx({
                bgcolor: 'supergreen',
              })
            }
          ]
        }
      }
    }

Decision

  • @siriwatknp I vote for adding callback to styleOverrides and deprecating the variants.
    • callback is more flexible in terms of combination of props ('===' && '!=='). It gives developers full power to do any customization and we, as maintainers, don't have to concern about it.
    • works in any case and I believe that people are already familiar with callback
    • the custom variants approach does not work with ('===' && '!=='), also it introduces the new syntax which we have to maintain in the future.
    • styleOverrides is what people are using the most (because it is from v4), so improve styleOverrides is better than adding new API (the custom variants)

@mnajdova
Copy link
Member Author

+1 for consolidating the API. I like better the styleOverrides as a key for the overrides, as variants as a term is misleading for most of the developers (they are confusing it with the variant prop available on some components). From a technical point of view, this would require only changing the typings (the callbacks are automatically supported).

What is important with this is that although the API is similar as before, there is an important change in the behavior (the keys here are slots, not a combination of props & slots as they were before). We MUST handle this breaking change and cover 100% of the migration of it, otherwise, developers won't be happy having to adjust the theme structure all over again. The same would go for the variants.

styleOverrides is what people are using the most (because it is from v4), so improve styleOverrides is better than adding new API (the custom variants)

Regarding this, I hope it is like this, but I am not sure as we were recommending variants over styleOverrides this last year.

@mnajdova
Copy link
Member Author

@siriwatknp would you like to close #28107 and #27415 and open a new issue for #28107 (comment)

@siriwatknp
Copy link
Member

@siriwatknp would you like to close #28107 and #27415 and open a new issue for #28107 (comment)

Sure, I am waiting to see other comments from the team if we are good with styleOverrides to support callback. cc @michaldudak @hbjORbj @oliviertassinari

@siriwatknp
Copy link
Member

Closed in favor of #30412 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion package: system Specific to @mui/system RFC Request For Comments
Projects
None yet
Development

No branches or pull requests

3 participants