Style Library Interoperability
While it is simple to use the JSS based styling solution provided by Material-UI to style your application, it is possible to use any styling solution you prefer, from plain CSS to any number of CSS-in-JS libraries.
This guide aims to document the most popular alternatives, but you should find that the principals applied here can be adapted to other libraries. We have provided examples for the following styling solutions:
Plain CSS
Nothing fancy, just plain old CSS. Why reinvent the wheel when it has been working for decades?
PlainCssButton.css
.button {
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: 3px;
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, .3);
}
PlainCssButton.js
import React from 'react';
import { Button } from '@material-ui/core';
export default function PlainCssButton() {
return (
<div>
<Button>Material-UI</Button>
<Button className="button">Plain CSS</Button>
</div>
);
}
Note: JSS injects its styles at the bottom of the <head>
. If you don't want to mark style attributes with !important, you need to change the CSS injection order, as in the demo.
Global CSS
Explicitly providing the class names to the component is too much effort? You can target the class names generated by Material-UI.
GlobalCssButton.css
.MuiButton-root {
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: 3px;
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, .3);
}
GlobalCssButton.js
import React from 'react';
import { Button } from '@material-ui/core';
export default function GlobalCssButton() {
return (
<div>
<Button>Global CSS</Button>
</div>
);
}
Note: JSS injects its styles at the bottom of the <head>
. If you don't want to mark style attributes with !important, you need to change the CSS injection order, as in the demo.
Styled Components
The styled()
method works perfectly on all of our components.
import React from 'react';
import styled from 'styled-components';
import { Button } from '@material-ui/core';
const StyledButton = styled(Button)`
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: 3px;
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, .3);
`;
export default function StyledComponents() {
return (
<div>
<Button>Material-UI</Button>
<StyledButton>Styled Components</StyledButton>
</div>
);
}
Controlling Priority
Note: Both styled-components and JSS inject their styles at the bottom of the <head>
.
The best approach to ensuring styled-components styles are loaded last is to change the CSS injection order, as in the demo:
import { StylesProvider } from '@material-ui/styles';
<StylesProvider injectFirst>
{/* Your component tree.
Styled components can override Material-UI's styles. */}
</StylesProvider>
Another approach is to use the &&
characters in styled-components to bump up specificity by repeating the class name. You should avoid the usage of !important
.
Deeper elements
If you attempt to style a Drawer with variant permanent,
you will likely need to affect the Drawer's child paper element.
However, the paper is not the root element of Drawer and therefore styled-components customization as above will not work.
You need to use the classes
API of Material-UI.
The following example overrides the label
style of Button
in addition to the custom styles on the button itself. It also works around this styled-components issue by "consuming" properties that should not be passed on to the underlying component.
import React from 'react';
import styled from 'styled-components';
import { Button } from '@material-ui/core';
const StyledButton = styled(({ color, ...other }) => <Button {...other} />)`
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, 0.3);
& .MuiButton-label {
color: ${props => props.color};
}
`;
export default function StyledComponentsDeep() {
return (
<div>
<Button>Material-UI</Button>
<StyledButton color="papayawhip">Styled Components</StyledButton>
</div>
);
}
The above demo relies on the default classes
values but you can provide your own class name: .label
.
import React from 'react';
import styled from 'styled-components';
import { Button } from '@material-ui/core';
const StyledButton = styled(({ color, ...other }) => (
<Button classes={{ label: 'label' }} {...other} />
))`
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, 0.3);
& .label {
color: ${props => props.color};
}
`;
export default function StyledComponentsDeep() {
return (
<div>
<Button>Material-UI</Button>
<StyledButton color="papayawhip">Styled Components</StyledButton>
</div>
);
}
ThemeProvider
Material-UI has a rich theme structure that you can leverage for the color manipulations, the transitions, the media queries, and more.
Portals
The Portal provides a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. Because of the way styled-components scopes its CSS, you may run into issues where styling is not applied.
For example, if you attempt to style the Menu of a Select component using the property MenuProps
,
you will need to pass along the className
property to the element being rendered outside of it's DOM hierarchy.
The following example shows a workaround:
import React from 'react';
import styled from 'styled-components';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
const StyledMenu = styled(({ className, ...props }) => (
<Menu {...props} classes={{ paper: className }} />
))`
box-shadow: none;
border: 1px solid #d3d4d5;
li {
padding-top: 8px;
padding-bottom: 8px;
}
`;
CSS Modules
It's hard to know the market share of this styling solution as it's dependent on the bundling solution people are using.
CssModulesButton.css
.button {
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: 3px;
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, .3);
}
CssModulesButton.js
import React from 'react';
// webpack, parcel or else will inject the CSS into the page
import styles from './CssModulesButton.css';
import { Button } from '@material-ui/core';
export default function CssModulesButton() {
return (
<div>
<Button>Material-UI</Button>
<Button className={styles.button}>CSS Modules</Button>
</div>
);
}
Note: JSS injects its styles at the bottom of the <head>
. If you don't want to mark style attributes with !important, you need to change the CSS injection order, as in the demo.
Emotion
The css
prop
Emotion's css() method works seamlessly with Material-UI.
/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import { Button } from '@material-ui/core';
// We just assign them the Button's className attribute
export default function EmotionButton() {
return (
<div>
<Button>Material-UI</Button>
<Button
css={css`
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: 3px;
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, 0.3);
`}
>
Emotion
</Button>
</div>
);
}
Note: JSS injects its styles at the bottom of the <head>
. If you don't want to mark style attributes with !important, you need to change the CSS injection order, as in the demo.
The styled()
API
It works exactly like styled components. You can use the same guide.
React JSS
Material-UI's styling solution shares many building blocks with react-jss. We went ahead and forked the project in order to handle our unique needs, but we're working to merge the changes and fixes from Material-UI back to react-jss.
import React from 'react';
import PropTypes from 'prop-types';
import injectSheet from 'react-jss';
import { Button } from '@material-ui/core';
const styles = {
button: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
borderRadius: 3,
border: 0,
color: 'white',
height: 48,
padding: '0 30px',
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
},
};
function ReactJssButton(props) {
return (
<div>
<Button>Material-UI</Button>
<Button className={props.classes.button}>react-jss</Button>
</div>
);
}
ReactJssButton.propTypes = {
classes: PropTypes.object.isRequired,
};
export default injectSheet(styles)(ReactJssButton);
Glamor
A good way to apply styles with Glamor is using the css() function and then classnames to get them as strings:
import React from 'react';
import { css } from 'glamor';
import { Button } from '@material-ui/core';
const buttonStyles = {
background: "linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)",
borderRadius: 3,
border: 0,
color: "white",
height: 48,
padding: "0 30px",
boxShadow: "0 3px 5px 2px rgba(255, 105, 135, .30)"
};
// Then we just assign them the Button's className attribute
export default function GlamorButton() {
return (
<div>
<Button>Material-UI</Button>
<Button {...css(buttonStyles)}>Glamor</Button>
</div>
);
}
Note: Both Glamor and JSS inject their styles at the bottom of the <head>
. If you don't want to mark style attributes with !important, you need to change the CSS injection order, as in the demo.