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

[ButtonGroup] Determine first, last and middle buttons to support different elements with correct styling #38520

Conversation

ZeeshanTamboli
Copy link
Member

@ZeeshanTamboli ZeeshanTamboli commented Aug 17, 2023

Based on point 2 of #29514 (comment).

Fixes #31210
Fixes #29514

Decided to tackle this after reviewing PR #38403.

Before: https://codesandbox.io/s/lively-http-3w24nw?file=/src/App.tsx
After: https://codesandbox.io/s/quizzical-glitter-kgrmyn

@mui-bot
Copy link

mui-bot commented Aug 17, 2023

Netlify deploy preview

https://deploy-preview-38520--material-ui.netlify.app/

@material-ui/core: parsed: +0.11% , gzip: +0.12%

Bundle size report

Details of bundle changes (Toolpad)
Details of bundle changes

Generated by 🚫 dangerJS against c5f8b76

@ZeeshanTamboli ZeeshanTamboli changed the title [ButtonGroup] Determine first and last buttons to support different elements with correct styling [ButtonGroup] Determine first, last and middle buttons to support different elements with correct styling Aug 17, 2023
@ZeeshanTamboli ZeeshanTamboli marked this pull request as ready for review August 17, 2023 13:04
@ZeeshanTamboli ZeeshanTamboli requested a review from a team August 17, 2023 13:33
boxShadow: 'none',
}),
},
[`& .${buttonGroupClasses.firstButton},.${buttonGroupClasses.middleButton}`]: {
Copy link
Member

Choose a reason for hiding this comment

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

@ZeeshanTamboli Instead of exposing the className, how about using just data-* attribute like:

  • data-first-child
  • data-last-child

No need for middle because we can use CSS :not to target middle children like this:
.${buttonGroupClasses.root}:not([data-first-child], [data-last-child])

Copy link
Member Author

@ZeeshanTamboli ZeeshanTamboli Aug 18, 2023

Choose a reason for hiding this comment

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

@siriwatknp I had thought about that and also referred Joy UI's ButtonGroup component code. The reason I added middle class is because then the :not selector will select the wrapping elements instead of button. As an example, in the case of the Tooltip shown in the CodeSandbox provided in the description it will select the Tooltip's span elements for:

<ButtonGroup>
  <Tooltip title="tooltip">
    <Button>Enabled</Button>
  </Tooltip>
  <Tooltip title="tooltip">
    <span>
      <Button disabled>Disabled</Button>
    </span>
  </Tooltip>
  <Tooltip title="tooltip">
    <span>
      <Button disabled>Disabled</Button>
    </span>
  </Tooltip>
</ButtonGroup>

And span is also needed to show the tooltip on disabled buttons - https://mui.com/material-ui/react-tooltip/#disabled-elements. Related issue #29514. The :not selector, however, won't target nested elements, such as a button inside a tooltip.

Regarding exposing classes, offering customization options to users might be a good idea. However, if desired, I could also use data-first-child, data-middle-child, and data-last-child attributes. Let me know your preference.

Copy link
Member

Choose a reason for hiding this comment

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

Alright, let's try data-middle-child instead of classes so that we don't expose too much API at this point.

Copy link
Member Author

Choose a reason for hiding this comment

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

@siriwatknp Done.

Copy link
Member

Choose a reason for hiding this comment

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

@siriwatknp, why not classes? We tend to use classes everywhere in Material UI for styling.

Copy link
Member Author

@ZeeshanTamboli ZeeshanTamboli Sep 6, 2023

Choose a reason for hiding this comment

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

I rolled back to use classes now.

@oliviertassinari
Copy link
Member

oliviertassinari commented Aug 18, 2023

@ZeeshanTamboli Please don't ping the core group for PR reviews that are on sub-product scopes. This creates too much notification noise.

Screenshot 2023-08-18 at 18 28 32

Instead, this is a PR for the ButtonGroup, you can ask for a review from one of the maintainers https://www.notion.so/mui-org/Components-Inputs-ecd48c9afe354bda8ecda3e96abc8c3c.

Screenshot 2023-08-18 at 18 34 28

Thanks

@oliviertassinari oliviertassinari added the component: button This is the name of the generic UI component, not the React module! label Aug 18, 2023
Copy link
Member

@DiegoAndai DiegoAndai left a comment

Choose a reason for hiding this comment

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

Hey @ZeeshanTamboli! sorry for the late review, I left some questions

@ZeeshanTamboli
Copy link
Member Author

Can this PR be reviewed further?

@DiegoAndai
Copy link
Member

@ZeeshanTamboli

Can this PR be reviewed further?

The logic looks good to me, but I agree with @michaldudak points:

  • Using classes seems to be the way to implement something like this in Material UI. Data attributes would be unexpected for users.
  • With this in mind, we should add tests to ensure the classes are applied correctly. The regression test won't cover all cases. For example, imagine we implement this using certain CSS classes and later refactor to rename them. If the refactoring is done well, the regression test will continue to work, but the classes might have changed, which might break the apps of users relying on them.

@ZeeshanTamboli
Copy link
Member Author

@DiegoAndai I made the changes, switching from data attributes to class names. I've also relocated the styles from the MuiButtonGroup-grouped className. This change may appear substantial in the code diff. We avoided targeting the first, middle, and last class names within the grouped classname to prevent increasing specificity, making it easier for users to override styles using the theme's styleOverrides or the sx prop. Previously, we applied styles using :first-of-type and :last-of-type selectors only to buttons with the MuiButtonGroup-grouped classname so it had to be inside the grouped class. This is no longer the case.

Additionally, I've included unit tests. So, if I understand correctly, these tests are added to ensure that we don't unintentionally introduce breaking changes when modifying the classes, is that right?

Copy link
Member

@DiegoAndai DiegoAndai left a comment

Choose a reason for hiding this comment

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

@ZeeshanTamboli thanks for applying the changes 😊

I agree with the specificity change 👍🏼

These tests are added to ensure that we don't unintentionally introduce breaking changes when modifying the classes, is that right?

Exactly.

I've added below another idea that came to mind.

packages/mui-material/src/Button/Button.js Outdated Show resolved Hide resolved
Copy link
Member

@DiegoAndai DiegoAndai left a comment

Choose a reason for hiding this comment

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

LGTM 🚀

This should go on the highlights of next release, nice improvement!

@ZeeshanTamboli ZeeshanTamboli merged commit 95e41fd into mui:master Sep 8, 2023
8 checks passed
@ZeeshanTamboli ZeeshanTamboli deleted the determine-first-last-buttons-in-button-group branch September 8, 2023 14:25
xcode-it pushed a commit to xcode-it/material-ui that referenced this pull request Sep 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: button This is the name of the generic UI component, not the React module! component: ButtonGroup The React component. package: material-ui Specific to @mui/material
Projects
None yet
6 participants