8
minutes
Mis à jour le
7/10/2019


Share this post

We will see how to style Material UI components with the library styled-components. Among the edge cases we will cover are: overriding Material UI's theme, prioritize the CSS rules of styled…

#
CSS
#
Front-end

We will see how to style Material UI components with the library styled-components. Among the edge cases we will cover are: overriding Material UI's theme, prioritize the CSS rules of styled components and override classes other than root of Material UI components.

You can play with the code snippets present in this tutorial with the following codesandbox link: https://codesandbox.io/embed/6lmnv4457z

Why Material UI and styled-components?

Material UI is a great component library that emulates Google’s Material Design. I choose to use it on each of my React web apps. And I am not alone: with more than 42k stars on github, it is the most popular component library for React.

Styled-components is another great library used to style React components. We do so by defining React “styled” components without CSS classes. Indeed, these styled components take CSS rule blocks as input. With 20k stars on github, it seems to be a no-brainer for many other web app developers too.

Some of the advantages of styled-components:

  • Large and active community
  • Explicit and exhaustive documentation
  • Template literal syntax for CSS. That means if you can write normal CSS, you can style components without having to learn a new syntax.
  • Sass support: write your style in a easier way to understand and with less lines of code.
  • The components’ code base is reduced: no style object in the render()method, no need of a multitude of conditional class names. This means you can focus on the logical structure of your React components.
  • Render CSS conditionally using props.

The problem

Material UI was designed to be used from the get-go with its own styling solution, implemented over JSS, as opposed to using styled-components.

Fortunately, Material UI has made it simple to use other styling solutions. Therefore, if you want to leverage the advantages of both Material UI and styled-components, wait no longer and read the rest of this article.

The 5 steps to mastery

1. Use Material UI’s JSS classes once for overriding Material UI original theme

Even though our objective is to style our web app using styled-components, we should not be afraid of using Material UI’s theme feature. The theme specifies the default style rules of the MUI components, such as color, level of shadow, etc…The theme enables us to create a pretty good base for our style. To illustrate the usage of Material UI’s theme, we will give a red background color to all our buttons, with a green background color on hover.

First create a theme.js file in your root folder

import { createMuiTheme } from "@material-ui/core/styles";

export default createMuiTheme({
  overrides: {
    MuiButton: {
      root: {
        fontWeight: "bold",
        backgroundColor: "red",
        margin: "10px",
        "&:hover": {
          backgroundColor: "green"
        }
      }
    }
  }
});

Then, we have to provide the theme defined above to the app, using the MuiThemeProvider. The MuiThemeProvider takes as prop a theme and injects it into the application. We encapsulate our app in theMuiThemeProvide as follow


import React, { Component } from "react";
import ReactDOM from "react-dom";
import MuiThemeProvider from "@material-ui/core/styles/MuiThemeProvider";
import Button from "@material-ui/core/Button";

import theme from "./theme";

class App extends Component<> {
  render() {
    return (

        

    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(, rootElement);

As you have just seen, to customize a specific instance of material UI components within our app, we provided to our theme the name and class of the component. This name and the class can be found in the CSS section of the API page of the Material UI components, for example https://material-ui.com/api/button/#css.

2. Use the styled() method to style your Material UI components

The styled() method from styled-components takes as input a React component and outputs another React component with a different style. It is useful as it enables you to style your component using the exact same syntax as in your typical CSS stylesheet. It works as follow:


import styled from "styled-components";
import Button from "@material-ui/core/Button";

export default styled(Button)`
  color: white;
  background-color: blue;
  height: 80px;
`;

❗️❗️❗️ Warning ❗️❗️❗️ : if you made your app exactly as in the previous steps, you should see that some of the CSS rules defined in the styled component are overridden by the defaults of Material UI, such as color andbackground-color. This is because the CSS injected by Material-UI to style a component has the highest specificity possible as the <link> is injected at the bottom of the <head> in the index.html file, in order to ensure the components always render correctly.

You might, however, want to override these styles if you intend to fully use styled-components. This leads us to the next step.

3. Prioritize the CSS rules of your styled-components over those of the JSS

1st method: increase specificity by repeating the class name

To ensure styled-components styles are applied before JSS styles, you can use use the ampersand (&) character in styled-components, which is equivalent to repeating the class name. The ampersand character is used to refer back to the main component. This solution applied to our example gives the following


import styled from "styled-components";
import Button from "@material-ui/core/Button";

export default styled(Button)`
  && {
    color: white;
    background-color: blue;
    height: 80px;
  }
`;

The disadvantage of this approach is that you have to use it for every styled component whose style specificity does not suit your needs. Not very DRY (Don't Repeat Yourself)!

2nd method: modify the CSS injection order

JSS provides a mechanism to handle specificity issues. By adjusting the placement of the insertionPoint within your HTML <head>, you can control the order in which the CSS rules are applied to your components.

The simplest approach is to add an HTML comment that determines where JSS will inject the styles. However, you may have been using create-react-app to kickstart your project. Create React App strips HTML comments when creating the production build. To get around the issue, you can provide a DOM element as the JSS insertion point.

First, place the insertion point as a DOM element at the top of <head>:

<head>
<noscript id="jss-insertion-point"></noscript>
<link href="..." />
</head>

Then, import JssProvider and other utility functions in your root component. You have to wrap your root component as follow:


import React, { Component } from "react";
import ReactDOM from "react-dom";
import MuiThemeProvider from "@material-ui/core/styles/MuiThemeProvider";

import JssProvider from "react-jss/lib/JssProvider";
import { create } from "jss";
import { createGenerateClassName, jssPreset } from "@material-ui/core/styles";

import Button from "@material-ui/core/Button";
import theme from "./theme";
import SimpleStyledButton from "./SimpleStyledButton";

const generateClassName = createGenerateClassName();
const jss = create({
  ...jssPreset(),
  // Define a custom insertion for injecting the JSS styles in the DOM
  insertionPoint: document.getElementById("jss-insertion-point")
});

class App extends Component<> {
  render() {
    return (


          

            Simple button styled with styled-components



    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(, rootElement);

4. Dynamically style your components while avoiding warnings related to DOM attributes

Your styled components are still components: you can pass them props to style them dynamically! However, to avoid warnings related to props passed directly to the underlying DOM element, you have to decompose what props you actually pass to the overriden Material UI component. An example of such decomposition follows:


import React from "react";
import styled from "styled-components";
import Button from "@material-ui/core/Button";

export default styled(({ color, ...otherProps }) => <Button {...otherProps} />)`
  color: ${props => props.color};
`;

5. Override other classes than root

There are two things you might do while doing a “complex” styling of your Material UI component:

  1. Style the child of your component. For example, the <span> element that wraps the children of a Material UI Button can be styled through the class label. However, this is not the root element of Button and therefore styled-components customization as above will not work.
  2. Style your component with a different style according to the class used, such as disabled. Similarly as above, if you target only the rootclass, you will not be able to style your Button in its disabled state.

The most reliable approach is to use the classes property to introduce an override style, and then style it with higher specificity with selectors. Note that the styled-components' CSS preprocessor is stylis, which supports css-like syntax for automatically nesting styles.

The following example overrides the label and disabled styles of Button in addition to the custom styles on the button itself:


import React from "react";
import styled from "styled-components";
import Button from "@material-ui/core/Button";

export default styled(({ color, ...otherProps }) => (
  <Button {...otherProps} classes={{ disabled: "disabled", label: "label" }} />
))`
  color: ${props => props.color};

  & .label {
    background-color: purple;
  }

  &.disabled {
    color: black;
    background-color: orange;
    .label {
      background-color: green;
    }
  }
`;

Endnotes

I believe I have shown you all the possible edge-cases that can happen when using the Material UI with styled components. While I chose Material UI as my component collection, you should be able to use the same styling techniques for any other component library.

Therefore, you should not have any problem styling your components in a React app from now on!