I migrated from Mui 4 to 5 and wonder how to use class names. If I want to apply certain styles to just one component there is the SX property. However, I'm struggling with using the same class for multiple components. In v4 my code looked like this:
export const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
padding: theme.spacing(1),
margin: 'auto',
},
})
)
I could import this useStyles hook in any component and use it like this:
const classes = useStyles()
...
<div className={classes.root}>...</div>
This docs say, that I can 'override styles with class names', but they don't tell how to do it: https://mui.com/customization/how-to-customize/#overriding-styles-with-class-names
Do I have to put these styles in an external CSS file?
.Button {
color: black;
}
I would rather define the styles in my ts file.
I also found this migration guide: https://next.material-ui.com/guides/migration-v4/#migrate-makestyles-to-emotion
I don't like approach one, because using this Root wrapper, it is inconvenient to apply a class conditionally. (Especially for typescript there is some overhead) Approach two comes with an external dependency and some boilerplate code.
Ideally I would use styles like this, perhaps with one rapper function around the styles object:
export const root = {
padding: theme.spacing(1),
margin: 'auto',
}
<div className={root}>...</div>
Of course, the last approach doesn't work, because className wants a string as input. Does anybody know an alternative with little boilerplate code?
I suggest you take a look at emotion's documentations for details. The sx prop is actually passed to emotion.
You can do something like this:
const sx = {
"& .MuiDrawer-paper": {
width: drawerWidth
}
};
<Drawer sx={sx}/>
Equivalent to MUI v4
const useStyles = makeStyles({
drawerPaper: {
width: drawerWidth,
}
});
const classes = useStyles();
<Drawer
classes={{
paper: classes.drawerPaper,
}}
/>
I'm in the same boat, about six months behind, i.e., starting to make the transition to v5 from v4 now... Just when I thought I had a handle on it all!
Having read this post and trying a few things out, I was able to replicate the ability to re-use a chunk of css. I'm a big fan of what used to be the overrides prop; that feature hasn't gone away, it's just under a different prop (loosely speaking). Regardless, I mention it because it provides access to what I like a lot about css: selectors.
To hit all MUI-Drawers my pref is for whatever the new overrides is. For targeted reuse of css I like the following:
import { reuseThisCss } from 'sharedCss`;
export default styled(Drawer)(({ theme, ownerState }) => {
...
return {
'& .MuiDrawer-paper': {
boxShadow: xxl,
border: 'none',
'& .MuiListItemText-root': reuseThisCss,
},
};
export default ThisSpecificDrawerVariant;
Note: The focus is not on using styled (It's not my goto approach).
The css in the return value is the equivalent to the following css: .MuiDrawer-paper .MuiListItemText-root {...}.
This says, "select all .MuiListItemText-root under the .MuiDrawer-paper parent. If I want to optimize the render, while increasing the dependency on a specific hierarchy, I'll specify/expand on the selector that much more with whatever lies between the .MuiDrawer-paper and MuiListItemText-root. For instance, in my case:
...
return {
'& .MuiDrawer-paper': {
boxShadow: xxl,
border: 'none',
'& > a > li > div > .MuiListItemText-root': reuseThisCss,
},
};
Finally, per a question in the comments, generally this will not prevent a nested application of the style. In my experience, marking each level with a className is useful. I only "mark" the element that signals the start of a new level. So, if it were Drawer in the above example, I would start the css selector with .MUI-Drawer.level-3. The rest of css remains the same.
I still have not figured out if whether setting the className dynamically remains a performant and sufficiently flexible goto... TBD.