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

[Accordion] Add Joy UI Accordion components #38164

Merged
merged 38 commits into from
Aug 22, 2023

Conversation

siriwatknp
Copy link
Member

@siriwatknp siriwatknp commented Jul 26, 2023

Preview: https://deploy-preview-38164--material-ui.netlify.app/joy-ui/react-accordion/

closes #36281. We have to roll a custom implementation as Base UI isn't available mui/base-ui#25 yet.

The Accordion family reuses styles from the List family.

AccordionGroup <-> List
Accordion <-> ListItem
AccordionSummary <-> ListItemButton

Joy UI Accordion uses CSS Grid for the accordion detail to let developers use CSS transition to animate the open/closed state.


@siriwatknp siriwatknp added component: accordion This is the name of the generic UI component, not the React module! package: joy-ui Specific to @mui/joy design: joy This is about Joy Design, please involve a visual or UX designer in the process new feature New feature or request labels Jul 26, 2023
@mui-bot
Copy link

mui-bot commented Jul 26, 2023

Netlify deploy preview

@mui/joy: parsed: +2.08% , gzip: +2.01%

Bundle size report

Details of bundle changes (Toolpad)
Details of bundle changes

Generated by 🚫 dangerJS against 69d7cfa

Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

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

Great to see movement on the accordion 👍

I wonder about the order we create this vs. the one in Base UI.

More ideas to push it further:

  1. For the animation duration, I think that getAutoHeightDuration could make a difference in how great it feels, Material UI is following this duration curve based on the height, to control the transition px/s
Screenshot 2023-07-27 at 15 31 52
  1. We will likely need overflowAnchor
  2. I think that we will need to consider the performance implication of mounting the whole accordion details list.
  3. This makes me think that we could start to support Support for prefers-reduced-motion #16367

adding @DiegoAndai to the loop, as the owner of the Accordion component (we are in draft mode now, so no need to review, I came here from https://twitter.com/siriwatknp/status/1684042706849505280).

>
<Radio value="0.3s linear" label="Linear" />
<Radio value="0.4s ease" label="Easing" />
<Radio value="0.8s cubic-bezier(0.68, -0.6, 0.32, 1.6)" label="Bouncy" />
Copy link
Member

@oliviertassinari oliviertassinari Jul 27, 2023

Choose a reason for hiding this comment

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

It takes 277ms for the accordion to start moving, I don't think that we can't have this transition curve, per https://web.dev/fid/#what-is-a-good-fid-score. For comparison, with Easing, I measure this at 27ms.

Suggested change
<Radio value="0.8s cubic-bezier(0.68, -0.6, 0.32, 1.6)" label="Bouncy" />

Instead, I think that we could have a small bounce at the end of the animation like https://dribbble.com/shots/20711653-Side-panel-framework-for-Opkey-s-no-code-automation-tool?

<Radio value="mix" label="Mix" />
</RadioGroup>
<AccordionGroup
transition={
Copy link
Member

Choose a reason for hiding this comment

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

Would it be clearer if this was customized with CSS and the sx prop? Developer would have direct access to their CSS animation design tokens, like duration, easing, etc.

What problem does the transition prop solve better?

Copy link
Member Author

@siriwatknp siriwatknp Aug 3, 2023

Choose a reason for hiding this comment

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

I thought about it as well. With transition prop, developers don't have to remember and specify both properties grid-template-rows and padding.

Also, if you want to customize the transition for both initial and expanded state in CSS, you will need to do this:

<AccordionGroup
  sx={{
    // actually you don't need to use CSS variables here but the amount of code to write is likely the same.
    '--AccordionDetails-transition': `grid-template-rows 0.2s, padding-block 0.2s`,
        [`& .${accordionDetailsClasses.root}.${accordionDetailsClasses.expanded}`]: {
          '--AccordionDetails-transition': `grid-template-rows 0.3s, padding-block 0.3s`,
        },
  }}
/>

whereas with transition prop:

<AccordionGroup
  transition={{
    initial: '0.2s',
    expanded: '0.3s',
  }}
/>

Comment on lines 14 to 18
<ToggleButtonGroup
size="sm"
buttonFlex={1}
value={size}
onChange={(event, newValue) => setSize(newValue)}
Copy link
Member

Choose a reason for hiding this comment

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

There can be no value selected, expected?

Screenshot 2023-07-27 at 15 35 58

Copy link
Member Author

Choose a reason for hiding this comment

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

How to reproduce it?

Copy link
Member

@oliviertassinari oliviertassinari Aug 5, 2023

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, I don't think so. We should let developers handle by themselve.

docs/data/joy/components/accordion/AccordionUsage.js Outdated Show resolved Hide resolved
setTransition(event.target.value);
}}
>
<Radio value="0.3s linear" label="Linear" />
Copy link
Member

@oliviertassinari oliviertassinari Jul 27, 2023

Choose a reason for hiding this comment

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

This easing makes me feel uncomfortable. What if instead, we were slowing the default animation (for illustration)? And/Or have it to be instant to illustrate prefers-reduced-motion?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the default animation/transition is out of scope from this PR that's why the demo illustrates how to add transitions.

@zanivan mentioned the default transition for Joy as well and I think it should be done separately so that each component does not need to wait to roll out.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think adding default animations/transitions to Joy UI would be really helpful. It could improve the microinteractions on components and potentially become a standout feature that sets Joy UI apart from competitors. Also, if we incorporate the Joy UI design language into Base UI, it would further differentiate the two products.

All in all, I think we can polish out a bit these animations, the easing is indeed a bit off, mostly on the bouncing demo—at least for me. Are there any workarounds to improve these animations before coming up with the default transition?

Copy link
Member

@oliviertassinari oliviertassinari Aug 5, 2023

Choose a reason for hiding this comment

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

I think the default animation/transition is out of scope from this PR that's why the demo illustrates how to add transitions.

@siriwatknp Ah sorry, I used the wrong terminology. By "default animation", I meant the one applied on the demo. I didn't consider the animation of the component bare.

But actually, this connects well to point 1. in #38164 (review). This feels OK, maybe a 10% faster would be good (to move to great, I think it would take a different easing IMHO):

Screen.Recording.2023-08-05.at.19.23.16.mov

and this feels too fast; 40% slower would be good (to move to great, I think it would take a different easing IMHO):

Screen.Recording.2023-08-05.at.19.25.07.mov

Copy link
Member

@oliviertassinari oliviertassinari Aug 5, 2023

Choose a reason for hiding this comment

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

I think we can also see this bug in this animation: the children isn't stable, "The Accordion Group supports the…" moves during the transition. So to start reading the content, you have to wait for the whole transition to finish

Screen.Recording.2023-08-05.at.19.31.20.mov

To compare with how it feels stable, e.g. https://ui.shadcn.com/docs/components/accordion. I feel stable is better UX.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Jul 29, 2023
@siriwatknp
Copy link
Member Author

I wonder about the order we create this vs. the one in Base UI.

For the Accordion to match WAI ARIA guide, using an internal hook from @mui/utils is enough.

We will likely need overflowAnchor

Got it.

I think that we will need to consider the performance implication of mounting the whole accordion details list.

Why? I think there will be a rare case to think in terms of performance which I think we can leave to the developer to decide.

@oliviertassinari
Copy link
Member

oliviertassinari commented Aug 5, 2023

Why? I think there will be a rare case to think in terms of performance which I think we can leave to the developer to decide.

@siriwatknp I think it's the same problem as in #21250. I think that the default of mounting everything is best, agree. The point I lead to is: How can developers unmount what's not visible with Joy UI without breaking animations?

Radix UI has the forceMount prop, by default it unmounts, and when applied to mounts: https://www.radix-ui.com/docs/primitives/components/accordion & https://codesandbox.io/p/sandbox/wizardly-zeh-dp5ng6?file=%2FApp.jsx%3A13%2C1.
Material UI does the opposite and allows developers to control mounting behavior: https://mui.com/material-ui/react-accordion/#performance.

We will likely need overflowAnchor

It fixed this strange bug: #22152.

For the Accordion to match WAI ARIA guide, using an internal hook from @mui/utils is enough.

I was thinking of it in terms of priority. The alternative route would be to open this PR on Base UI first, and then Joy UI.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Aug 7, 2023
@siriwatknp siriwatknp marked this pull request as ready for review August 7, 2023 05:10
@siriwatknp siriwatknp requested a review from zanivan August 7, 2023 09:52
@siriwatknp
Copy link
Member Author

@zanivan Updates:

  • The divider appears by default which can be hidden by <AccordionGroup disableDivider> prop
  • The default transition is 0.2s ease.
  • Adjusted padding-bottom to increase spacing between AccordionSummary and Details between accordions.
  • I am hesitating to remove the solid variant at this point. I feel like it's the presenting issue more than the implementation so I decided to remove the Usage demo for now.
  • I did not touch size-related properties. I would not add more CSS to it at this point because you can simply customize the font-size with just one line.
  • Updated the last common example. The AccordionDetails should have only one for each accordion.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Aug 10, 2023
@zanivan
Copy link
Contributor

zanivan commented Aug 10, 2023

  • I don't know if we should remove the Usage demo, since we have it in all interactive components, it would be inconsistent.
    So this is a matter of choosing what tradeoff we will have: removing the Usage demo that'll result in an inconsistency with other pages; or, keeping the Usage demo and the solid variant.
    Personally, I lean towards keeping the Usage demo, since we have more components with problematic variants like this—and this issue can be addressed in a separate PR, where we select which variants each component will have.

  • The https://deploy-preview-38164--material-ui.netlify.app/joy-ui/react-accordion/#styling-on-expansion doesn't seem to be rendering the border on the third item
    Screenshot 2023-08-10 at 08 41 59

Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

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

A quick review:

component = 'div',
color = 'neutral',
children,
indicator = <KeyboardArrowDown />,
Copy link
Member

Choose a reason for hiding this comment

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

This React element could be hoisted.

Comment on lines +10 to +13
/** Class name applied when the accordion is disabled. */
disabled: string;
/** Class name applied when the accordion is expanded. */
expanded: string;
Copy link
Member

Choose a reason for hiding this comment

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

The disabled and expanded classes are Accordion classes, why add them here as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

For styling purposes, without these classes, you will have to theme the AccordionSummary like this:

extendTheme({
  components: {
    JoyAccordion: {
      styleOverrides: {
        root: {
          [`.${accordionClasses.root}.${accordionClasses.expanded} &`]: {
             …styles
          }
        }
      }
    }
  }
})

whereas

extendTheme({
  components: {
    JoyAccordion: {
      styleOverrides: {
        root: {
          [`&.${accordionSummaryClasses.expanded}`]: {
             …styles
          }
        }
      }
    }
  }
})

Copy link
Member

Choose a reason for hiding this comment

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

I agree it's easier, but if we do it for the AccordionSummary component, shouldn't we do it for the other accordion components as well?

  • AccordionDetails has expanded but not disabled
  • AccordionGroup has neither

We should either add the classes to all or none. Otherwise, it might be confusing.

I would only have these on the root, I think the following is not a bad API:

extendTheme({
  components: {
    JoyAccordion: {
      styleOverrides: {
        root: {
          [`.${accordionClasses.expanded} &.${accordionSummaryClasses.root}`]: {
             …styles
          }
        }
      }
    }
  }
})

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Aug 21, 2023
@siriwatknp
Copy link
Member Author

  • I don't know if we should remove the Usage demo, since we have it in all interactive components, it would be inconsistent.
    So this is a matter of choosing what tradeoff we will have: removing the Usage demo that'll result in an inconsistency with other pages; or, keeping the Usage demo and the solid variant.
    Personally, I lean towards keeping the Usage demo, since we have more components with problematic variants like this—and this issue can be addressed in a separate PR, where we select which variants each component will have.
  • The https://deploy-preview-38164--material-ui.netlify.app/joy-ui/react-accordion/#styling-on-expansion doesn't seem to be rendering the border on the third item
    Screenshot 2023-08-10 at 08 41 59

I brought back the Usage demo and apply the variant to other components when it is solid. Also, fix the demo you mentioned.

@siriwatknp siriwatknp force-pushed the joy/accordion-component branch from 5bbe4bf to db26aa1 Compare August 21, 2023 10:57
Copy link
Contributor

@zanivan zanivan left a comment

Choose a reason for hiding this comment

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

Added some small tweaks to a demo, but it looks good to me! 🚀

@siriwatknp siriwatknp merged commit c832860 into mui:master Aug 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: accordion This is the name of the generic UI component, not the React module! design: joy This is about Joy Design, please involve a visual or UX designer in the process new feature New feature or request package: joy-ui Specific to @mui/joy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Joy] Add the Accordion component
5 participants