-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
[material-ui][Button] Add loading feature to Button #42987
Conversation
All functionality from loadingButton has been moved to Button in mui-material
Netlify deploy preview
IconButton: parsed: +4.61% , gzip: +3.47% Bundle size reportDetails of bundle changes (Toolpad) |
added Icon class to start and end icons, ran prettier, updated loadingButton tests to test Button. LoadingButton tests not to be merged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this @Gavin-10! I did a first pass and left some inline comments. Apart from that, two more things:
- The
LoadingButton
component implementation in mui-lab needs to be updated to just use the newly updatedButton
from mui-material. The Alert component in mui-lab is a good example of how to do this. - The
Button
usage docs must be updated:- The examples under the "Loading button" section must be updated to use
Button
and this section should be moved before the "File upload" section. - The "Experimental APIs" heading can be removed.
LoadingButton
shouldn't be listed in the API section at the end of the page.
- The examples under the "Loading button" section must be updated to use
Let me know if you have any doubts or if you need help.
Button.js variable names changed, extra classes deleted, loading button tests moved to button.test.js, pnpm-lock restored, last-run.json removed (hopefully)
Thank you so much @aarongarciah for the review! I have implemented all the suggested changes and almost ready to push again. I just have two quick questions. To remove the loading button from the API list do I need to just delete the .json and .js file from the API folder or are there more steps I need to do? Last, all of those extra props were generated when I ran pnpm proptypes and I'm just wondering why they need to be removed so I can have a better understanding for future contributions? Thank you so much. |
To remove
I should have left the comment in the .d.ts file instead of the .js file. Every time you make a proptypes change (add, remove, or modify comments) you'll need to run Another common script is Take a look at https://github.com/mui/material-ui/blob/next/CONTRIBUTING.md#sending-a-pull-request if you have doubts and feel free to ping me anytime you get stuck. Happy coding! |
Extra button classes removed, loading button tests removed and docs removed from API list, loading button depreciated.
Everything should be about wrapped up now. I fixed the dependency issues and some minor styling issues with child elements. The test_unit and test_browser tests failing is expected and caused by the CircularProgress not having accessibility labels. I however do not know why test_e2e_website is failing. Once that is resolved though, I believe everything should be ready. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did another quick pass. We're currently focused on supporting the v6 release, but I'll get back to this PR once all feedback is tackled. Thanks for working on this!
@ZeeshanTamboli pushed the loading prop for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add tests for IconButton with loading state?
Added, thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I'm pumped. It has been 4 years since LoadingButton
was introduced!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed two commits recently. Looks good to me!
import ShoppingCartIcon from '@mui/icons-material/ShoppingCartOutlined'; | ||
|
||
const CartBadge = styled(Badge)` | ||
.${badgeClasses.badge} { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing selector per convention
.${badgeClasses.badge} { | |
&.${badgeClasses.badge} { |
import LoadingButton from '@mui/lab/LoadingButton'; | ||
import Button from '@mui/material/Button'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change goes in opposition to the initial API design decision, no? #21389. We used import LoadingButton from '@mui/lab/LoadingButton';
, we didn't use:
import Button from '@mui/material/Button';
<Button unstable_loading={true}>
The reason was in this dangerbot message:
Personally, as a user, I wouldn't want to use the Material UI Button if it loads a progress component that is different from the one that I want to use because it's bundle size bloat.
Was this change discussed? How do we feel about it?
Happy to move forward with a loading
prop though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a <Button loading>
is better than having <Button>
and <LoadingButton>
. I guess 9/10 projects would need a loading button so it's fine to bundle CircularProgress
to the Button
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this was discussed. Having a loading
prop in Button is universally established and I think it's preferable to merge LoadingButton
and Button
to reduce API surface and confusion (why having 2 components with almost the same exact API?), even if it means an increase in the bundle size.
Q: Is there a way we could dynamically import the progress component that would be compatible with all bundlers? Are dynamic imports universally supported?
Personally, as a user, I wouldn't want to use the Material UI Button if it loads a progress component that is different from the one that I want to use because it's bundle size bloat.
This also happens with component styles. Users load our components, which have all styles built-in and are included in the bundle, to later override them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: Is there a way we could dynamically import the progress component that would be compatible with all bundlers? Are dynamic imports universally supported?
@aarongarciah MUI X does this https://github.com/mui/mui-x/blob/a4481b6a661849d1a33b41aad86970a1e212ca69/packages/x-data-grid-premium/src/hooks/features/export/serializer/excelSerializer.ts#L24. It seems to work for them:
Screen.Recording.2024-11-19.at.16.34.51.mov
In the CJS the output is https://unpkg.com/browse/@mui/[email protected]/hooks/features/export/serializer/excelSerializer.js so it only works for ESM.
This wouldn't work for us here, since we would also need an async component, not React 18 friendly.
This also happens with component styles. Users load our components, which have all styles built-in and are included in the bundle, to later override them.
Yeah. Ok, so maybe it's fine. As long as we move to have the source to be clean to copy and paste from the npm package to a project codebase, then, a developer (e.g. me) would eject, and remove all the stuff unneeded, once it truly becomes a problem.
I have checked a couple of design system, they seem to all go with the loading prop pattern. e.g. https://polaris.shopify.com/components/actions/button. So yeah, assuming that we don't expect most people to wrap the MUI component to create their own system, but to either
- use it as is with theme customization
- or to decompose + recompose with a wrapper, this makes sense.
const loader = ( | ||
<ButtonLoadingIndicator className={classes.loadingIndicator} ownerState={ownerState}> | ||
{loading && loadingIndicator} | ||
</ButtonLoadingIndicator> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this conditional? I don't think this can work to render an empty DOM node when loading={false}
:
https://deploy-preview-42987--material-ui.netlify.app/material-ui/react-button/#basic-button. DOM size has an impact on performance, buttons that are likely to be rendered in the x100 in a list. Same applies with emotion, another styled() mounting point is more slowness to the page. The most important might be that this can communicate a feeling of "bloat" to developers.
At the very minimum, I think we need a comment to explain why it's here. As a developer looking at the dev tools then the source to try to understand this, I would be: "What?! Let's delete that" I wouldn't know the context around Google translate #35198.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's conditional, it won't fix #35198.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this can fly
May I ask why? what's the issue of it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's conditional, it won't fix
@siriwatknp I mean, what I don't understand is why are we not using the same fix that we used in #35198? Why are we always rendering an extra styled() element even when loading={false}
?
May I ask why? what's the issue of it?
I have tried to cover the problem with the initial comment: "DOM size has an impact on performance, buttons that are likely to be rendered in the x100 in a list. Same applies with emotion, another styled() mounting point is more slowness to the page. The most important might be that this can communicate a feeling of "bloat" to developers."
What do you think about those?
PR was reverted in #44478. |
All functionality from loadingButton has been moved to Button in mui-material
closes #42684
Closes #31235 (removes the wrong warning)
Preview: https://deploy-preview-42987--material-ui.netlify.app/material-ui/react-button/