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

[system] Add posibility to use props in style overrides #28867

Closed
wants to merge 16 commits into from
Closed

[system] Add posibility to use props in style overrides #28867

wants to merge 16 commits into from

Conversation

rajzik
Copy link
Contributor

@rajzik rajzik commented Oct 6, 2021

This change introduces posibility to use props inside theme components style overrides.

Example

const theme = createTheme({
  components: {
    MuiButton: {
      styleOverrides: {
        root: (props) => ({ ...(props.color === 'primary' && { color: 'pink' }) })
      }
    }
  }
})

This change is tested and typed and should not break previous behavior

closes #27415

Documentation:
https://deploy-preview-28867--material-ui.netlify.app/customization/theme-components/#props-inside-style-overrides

@rajzik
Copy link
Contributor Author

rajzik commented Oct 6, 2021

I would like to this in documentation. Can someone help me with that?

@mui-pr-bot
Copy link

mui-pr-bot commented Oct 6, 2021

Details of bundle changes

Generated by 🚫 dangerJS against feb9da7

@rajzik
Copy link
Contributor Author

rajzik commented Oct 8, 2021

@mnajdova or @oliviertassinari can you give me some feedback and guidance?

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 would document this as a new example under https://mui.com/customization/theme-components/#global-style-overrides

@rajzik
Copy link
Contributor Author

rajzik commented Oct 8, 2021

@mnajdova I have tried to add documentation for this feature, but I am not a great docs writer.

@rajzik
Copy link
Contributor Author

rajzik commented Oct 8, 2021

@mnajdova
Sadly, styled doesn't have access to the props directly. But ownerState can be used, this would mean that props must be forwarded (they currently are) to the styled component. I am not sure about this solution, but it is still better than nothing.

@mnajdova
Copy link
Member

mnajdova commented Oct 8, 2021

Sadly, styled doesn't have access to the props directly. But ownerState can be used, this would mean that props must be forwarded (they currently are) to the styled component. I am not sure about this solution, but it is still better than nothing.

What do you mean it doesn’t have access?

@rajzik
Copy link
Contributor Author

rajzik commented Oct 10, 2021

Sadly, styled doesn't have access to the props directly. But ownerState can be used, this would mean that props must be forwarded (they currently are) to the styled component. I am not sure about this solution, but it is still better than nothing.

What do you mean it doesn’t have access?

For example:

const Root = styled(ButtonBase, {
name: 'MuiButton',
})(({ theme }) => ({ }));

const Button = forwardRef(function Button(inProps, ref) {
  const props = useThemeProps({ props: inProps, name: 'MuiButton' });
  const ownerState = {
    ...props,
    color,
    component,
    disabled,
    disableElevation,
    disableFocusRipple,
    fullWidth,
    size,
    type,
    variant,
  };

  return <Root ownerState={ownerState}>{children}</Root>
});

In this example Root created by styled doesn't have the same props as component itself. We want to access Button props. But Root props don't have access to them. We can use ownerState that is passed to the component and slots.

@rajzik rajzik requested a review from mnajdova October 11, 2021 11:11
@rajzik rajzik requested a review from mnajdova October 13, 2021 08:12
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.

Looks good overall. I will test it more next week and merge it. Thanks a lot for the contribution 🙏

@rajzik
Copy link
Contributor Author

rajzik commented Oct 15, 2021

@mnajdova thank you. This would help us with our project a lot. And I am not sure why the prettier doesn't work on windows or my git configuration, can you maybe change gitattributes so it is config independent.

@mnajdova
Copy link
Member

@rajzik just an FYI I plan to test and merge this tomorrow :)

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.

It looks good to me!

@mnajdova mnajdova requested a review from siriwatknp October 21, 2021 13:37
@siriwatknp
Copy link
Member

@mnajdova Is this different from variants?

@rajzik
Copy link
Contributor Author

rajzik commented Oct 22, 2021

@siriwatknp
I believe so, not all components have variant (at least not typed). Also, you can style subcomponents with this code change.

Comment on lines 123 to 126
export type ComponentsOverrides = {
[Name in keyof ComponentNameToClassKey]?: Partial<
OverridesStyleRules<ComponentNameToClassKey[Name]>
OverridesStyleRules<ComponentNameToClassKey[Name], Name>
>;
Copy link
Member

Choose a reason for hiding this comment

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

This means that I can do:

MuiButton: {
  styleOverrides: {
    startIcon: props => {
      // props has type `ButtonProps`
      // but props contains only ownerState. see implementation in `/Button.js:315`
    }
  }
}

I think only root can be a function.

@siriwatknp
Copy link
Member

siriwatknp commented Oct 22, 2021

@siriwatknp I believe so, not all components have variant (at least not typed). Also, you can style subcomponents with this code change.

Sorry, I don't mean variant prop. I mean the variants inside theme.

createTheme({
  components: {
    MuiButton: {
      variants: [
        { props: { color: 'primary', customProp: true }, style: { ... } }, 
      ]
    }
  }
})

The above customization already existed. Is there any case that it could not achieve without using function? cc @mnajdova

@mnajdova
Copy link
Member

After spending a bit more time thinking about this, and considering @siriwatknp's review I think that we should consider the following: Currently we have two APIs for overrides in the theme

  1. theme.components[Component].styleOverrides - these are the style overrides that basically existed from 4.0
const theme = createTheme({
  components: {
    MuiButton: {
      styleOverrides: {
        root: { color: 'pink' }
      }
    }
  }
})
  1. theme.components[Component].variants - new API added shortly before v5 was released.
const theme = createTheme({
  components: {
    MuiButton: {
      variants: [
        { props: { color: 'primary', customProp: true }, style: { ... } }, 
      ]
    }
  }
})

Both of them were working with JSS and are working with emotion now. In my opinion, we should be dropping the styleOverrides long term in favor of the variants. Why? The variants API is much more flexible. With the ability we have now in v5 for extending colors/sizes etc, the styleOverrides is not scaling. For applying styles on the slots, we can use a classes subselectors, for example:

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

I was exploring even new API with #28107, but it is not really necessary at this moment.

The main motivation for this is that we should not have two APIs for doing the same thing. We could not drop the stylesOverrides when they were added, as it would require tremendous work in terms of breaking changes, but we could plan it for v6. If we agree that this is our long term goal, it doesn't make sense to introduce more API to it.

Sorry for the turnaround @rajzik but I am trying to think about what is the best option long term. Nevertheless, it was a great work.

@rajzik
Copy link
Contributor Author

rajzik commented Oct 26, 2021

@mnajdova No problem, I will close my PR and issue should be closed too.

@rajzik rajzik closed this Oct 26, 2021
@zannager zannager added the package: system Specific to @mui/system label Jan 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: system Specific to @mui/system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[system] Allow callbacks when defining styleOverrides inside the theme
5 participants