Material UI - Overriding styles using Root & using ClassName - reactjs

I'm new to material UI. While learning, I came to know out that styles of a material UI can be overridden with the rule name of the classes.
If I have an element - MenuItem where I just need to change the default styling of the text (such as fontFamily, fontWeight, fontSize)
According to the documentation available here https://material-ui.com/api/menu-item/ I used makeStyles hook and have overridden some properties of the root element of Menu-Item
Sample code
const useStyles = makeStyles((theme) => ({
menuItem: {
fontFamily: "Raleway",
}
}));
JSX code: <MenuItem onClick={handleClose} component={Link} to="/services" classes={{root: classes.menuItem}}>Services</MenuItem>
In one more tutorial, I found another way of overriding - with className like
const useStyles = makeStyles((theme) => ({
menuItem: {
fontFamily: "Raleway",
}
}));
JSX code: <MenuItem onClick={handleClose} component={Link} to="/services" className={classes.menuItem}>Services</MenuItem>
My question lies in this part className={classes.menuItem} and classes={{root: classes.menuItem}}
On using root -> I see the css properties getting added to the root element but on using className={classes.menuItem} I see a new class is added to the DOM. But Is there any difference with respect to the behaviour of the app between these 2 methods or is it just another way of doing it?
Thanks

From what I can tell having worked with Material UI, the difference is with what you're trying to do.
className={classes.menuItem} and classes={{root: classes.menuItem}} will both get you the results that you're expecting, as you've already discovered.
The distinctions are important when you start building custom themes, because Material UI allows you to apply classes to the components as a whole, meaning potentially comprised of other components, or pass along styles to the root elements if you need a higher specificity.
For example, consider the Stepper component.
classes={{root: classes.menuItem}} will override the root in the component, applying your styles.
className={classes.menuItem} will add an additional class to the component, leaving the underlying styles intact.

Related

How to style Material UI Dialog with Tailwind?

Material UI Dialog is a portaled component. The way I understood it and saw it in action is that it renders its markup outside the React's root element.
It renders itself before the </body> tag.
Now I have encountered a problem because of this.
When user chooses the dark mode, I set a dark class on top-level element, one beneath the root element.
And on all components I can use dark variant to apply styles, like dark:bg-zinc-700.
But when I apply it the <Dialog /> component, it won't affect its style, though I can see that the class exists in the output.
<Dialog
PaperProps={{
className="dark:bg-zinc-700"
}}
How should I solve this problem? I know I can use sx to apply style. But that means I need to lose consistency and I also don't know how to translate Tailwind to sx. Thus I prefer to keep using Tailwind.
I solve this problem with this Link
MuiDialog: {
defaultProps: {
container: rootElement,
},
},
Check this
#HosseinFallah Looking back at your post I think this won't work because tailwind and material ui handle dark modes differently. However, you can target Material UI css without using sx. You can use the Dialog API classes in your css and apply tailwind colors on them like this in your global css:
.MuiDialog-paperScrollBody {
background-color: theme(colors.dark) !important;
}
Where dark is the custom dark color you've set in your tailwind.config.js
To add to the answer you can also set this for your whole app by wrapping it with the Mui's StyledEngineProvider. This way tailwind will be prioritized when injecting styling.
In your index.tsx
import { StyledEngineProvider } from '#mui/material';
const container: any = document.getElementById('root');
const root = createRoot(container);
root.render(
<Provider store={store}>
<React.StrictMode>
<StyledEngineProvider injectFirst>
<App />
</StyledEngineProvider>
</React.StrictMode>
</Provider>
);
Then this will be possible without needing to specify !important
<Dialog
PaperProps={{
className="dark:bg-zinc-700"
}}
Did you set the "important" property in the Tailwind config (tailwind.config.js) by chance?
If you set it to something like "#root" then it will only match the elements inside the #root element which is bypassed when MUI uses React Portals.
You could change it to something like "#tw" and then set your body's ID to "tw" so it will always match since Portals are always children of the body element.
if you completely interoperate to tailwindcss, see: https://mui.com/material-ui/guides/interoperability/#tailwind-css
i think this mistake occure in tailwindcss.config.js.
by adding another id to wrap dialog container and asign it to "important" property will solve this problem
You can increase the specificity of the TailwindCSS by using !important selector.
You can find more here https://tailwindcss.com/docs/functions-and-directives

Regular ClassName with Material UI

I've read some answers to similar questions but did not fully understand because of materialUI update where #mui/styles are depricated.
According to mui docs we can create custom styling using sx prop, smth like this
<Typography variant="h5" sx={{backgroundColor: 'red' }}>Header</Typography>
But when I use regular classNames in v5 it works well too:
//css
.makeRed {
backgroundColor: red
}
// jsx
<Typography variant="h5" className="makeRed">Header</Typography>
The question is - does using regular classes has pitfalls and I need to rewrite mui classes?
(have started my mUI jorney yesterday)
I've been brushing up on Material for a new job and I've found that if you want to make things more easily changeable and run faster you'll work through the framework. The purpose of Material is for enhanced reusability, so you'll want to work with that purpose and align your style in everything you do within the app towards everything being the same.
If anything your best bet is to do:
const useStyles = makeStyles({
makeRed: {
background-color: 'red'
}
})
export default useStyles;
Then in the actual component just have your classes const as.
const classes = useStyles();
<Typography className = {classes.makeRed} />

How can I access to change styles of inner items of a component in react and material ui?

How can I access to inner css classes of children of a component and add or change styles to/of them? like I want to change and customize material ui stepper steps circle font size and color and so on.
How can I write css classes like bellow:
.stepper circle {
font-size:18px;
}
or
.stepper .text {
font-size:18px;
}
thanks.
Thanks to #spakmad's answer, but that's not exactly what I meant, maybe my question was not clear enough. I meant how to write above mentioned CSSs in material ui object style classes format(classes injected with withStyle HOC).
I found my solution:
stepper:{
'& circle':{
fontSize: '18px'
}
}
and
stepper: {
'& .text': {
fontSize: '18px'
}
}
The very straightforward way to do it without having to worry about classes is by using the material-ui style prop. Like so,
<Stepper style={{ fontSize: '18px' }} />
This applies a style to the root element, which I assume to be a div or container of sorts, although it probably varies by the component.
More specifically, and what you probably want to do is use material-ui classes prop. That is, since you know exactly what classes you want to override, you can do so as follows,
<Stepper classes={{ text: { fontSize: '18px' }}} />
I use text here as a classname because in the question, .text appears to reference and already existing class. Since you're trying to increase the size of the font in this svg that comes with the Stepper. You'll need to get the class name applied to the svg and override it. In this case, one of its classnames is MuiSvgIcon-root-184 so you would expect to be able to do,
<Stepper classes={{ MuiSvgIcon-root-184: { fontSize: '18px' }}} />
This classname however is generated by material-ui dynamically based on the layout resulting from props and could be different across all renders.
TLDR
So, trusty className component and writing some css and component JSX as follows.
<Stepper className={'customStepper'} />
.customStepper svg: {
font-size: '18px !important',
}
You need to include !important to make sure this style is respected. Material UI by default puts its styles last in the document so they're normally overwriting anything else, but the !important spec should override the override.

React Material-UI styling active menu items

I'm trying to figure out how to apply css styles to :active and :hover states of a Material-UI Menu.
The docs say,
selectedMenuItemStyle | object | | Override the inline-styles of selected menu items.
But applying,
<Menu selectedMenuItemStyle={{ color: 'red'}}>
<MenuItem
style={ menuItemStyles }
primaryText={ pages.dashboard.title.toUpperCase() }
containerElement={<NavLink to={ `${pages.dashboard.slug}` } />} />
</Menu>
has no effect when I click on <MenuItem>
I've also tried React-Router's activeStyle and activeClassName which have no effect because Material-UI overrides them.
Anyone know how to apply :active and :hover correctly?
Have a look there : material-ui
Every component provides a className property. Those properties are always applied to the root element.
Note that CSS properties defined inline are given priority over those defined in a CSS class. You need to use !important to take precedence over the inline style.
try to add !important on your custom style to override material-ui like
.test-class:hover {
color: red !important
}

Material UI inline style not working

In Material UI, I want to set borderRadius on my buttons. Passing the style attribute seem to work for FlatButton but not for RaisedButton.
For RaisedButton, the borderRadius is applied to the parent <div> (which is necessary) but not to <button> itself (which is also necessary)
Is this a bug in Material UI? Or is this behaviour intended? If it's intended, then how do I make a RaisedButton with rounded corners?
import React from 'react';
import RaisedButton from 'material-ui/lib/raised-button';
import FlatButton from 'material-ui/lib/flat-button';
export default class MyButtons extends React.Component {
render() {
return (
<div>
<FlatButton label="flat button" style={{borderRadius: '25px'}}/> {/*works*/}
<RaisedButton label="raised button" style={{borderRadius: '25px'}} /> {/*does not work*/}
</div>
);
};
}
This is the intended behaviour, and says so in the docs. For the record, you would never want a style prop to be passed to multiple children as no styles would make sense across all children - and how deep in nesting would you apply them?
But I think you're mixing concerns here. Using style on a component should only ever effect the root element - and that's assuming the developer chose to pass along the style tag, which they did.
But what you're looking to do is not style the component, but style the elements of the component. What you want to do is use a CSS class:
<RaisedButton label="raised button" className="raised-button--rounded" />
.raised-button--rounded,
.raised-button--rounded button {
border-radius: 25px; /* assuming one is not already defined */
}
NB: The developers do not intend for you to change the component styles that they have not specifically exposed. Through this approach, you will run into issues eventually.

Resources