React and Material UI (MUI)
Published: 2022-05-09 13:54:53

---
title: React and Material UI (MUI)
published: true
date: 2021-01-08 00:00:00 UTC
tags: 
canonical_url: https://carl-topham.com//articles/react-material-ui-mui
---

When I first used Material UI, I struggled with a few concepts. I've written this quick overview to help get my head around it, and hopefully guide others to a quicker start.

I'm going to make a new project and then create some (horrible) styles!

## Create the project and add MUI

Create a project and install the Material UI package

```
npx create-react-app material-ui-playground


cd material-ui-playground


yarn add @material-ui/core
 

```

## Clean up the initial templates

Remove some unused contents (import of the styles) from the `index.js`

```
import React from 'react';
import ReactDOM from 'react-dom';
// import './index.css'; DELETE this line and the file
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

```

Replace the `App.js` content with the following:

```

const App = () => {
  return (
    <div>
      <h1>Material UI Playground</h1>
    </div>
  );
}

export default App;

```

## Creating a theme

First we need to define a [palette](https://material.io/resources/color/#!) to work with - This will define the core `color` and tones of the UI.

Then we can use the palette to [create a theme](https://material-ui.com/customization/palette/) that we can use around the site. It's not just the `color` that can be in a theme, but also all other properties such as `spacing` and `font-family`.

In my example we will be using colors only. You can import the core colors from the `mui` package and use them. They come with a range of shades built. We can also specify `light`, `dark` and `contrastText` colors for our palette, but if we don't MUI will automagically do this for us.

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

import { purple } from '@material-ui/core/colors';
import { amber } from '@material-ui/core/colors';
import { red } from '@material-ui/core/colors';

const theme = createMuiTheme({
    palette: {
        primary: {
            main: purple["500"],
            // We don't need to set the text colour as MUI will work this out
        },
        secondary: {
            main: amber["600"],
            // We will manually set the alternate colours
            light: amber["200"],
            dark: amber["900"],
            contrastText: '#222222'
        },
        error: {
            main: red["500"]
        },
        background: {
            default: '#fff',
        },
    },
});

export default theme;

```

Then in the `App.js` import the theme and theme provdier.

```
import { ThemeProvider } from '@material-ui/styles';

import theme from "./theme";

// ... the rest

```

Then wrap the returned DOM in a `<ThemeProvider />` like so:

```
// ... rest

const App = () => {
  return (
      <ThemeProvider theme={theme} >
        <div>
          <h1>Material UI Playground</h1>
        </div>
      </ThemeProvider>
  );
}

export default App;

```

Now the components within the `ThemeProvider` will all be able to use the theme we have just created. Let's use it.

We could just import the components directly into our `App` but to keep them nice and tidy (and reusable elsewhere) we will make a component!

Create a component `components/TitleBlock.index.jsx`. In this we will use the build in MUI Typography component. This takes a few props. We are going to set the `varient` to `h1` so we get a `<h1 /`> rendered, and give it a color to use. This is one of our colors we set up in the theme palette.

We're also going to use a `Divider` which will create a `<hr />`.

```
import Typography from "@material-ui/core/Typography";
import Divider from '@material-ui/core/Divider';

const TitleBlock = ({title}) => (
    <>
        <Typography variant={"h1"} color={"primary"} >{title}</Typography>
        <Divider />
    </>
)

export default TitleBlock

```

Now we can import it and use it in the `App.js`.

```
import { ThemeProvider } from '@material-ui/styles';

import theme from "./theme";
import TitleBlock from "./Components/TitleBlock";

const App = () => {
return (
    <ThemeProvider theme={theme} >
        <TitleBlock title="Material UI Playground" />
    </ThemeProvider>
);
}

export default App;

```

You should see something like this:

![TitleBlock render](https://carl-topham.com/content/articles/react-material-ui-mui/mui-titleblock.png)

Material UI contains a full set of built in components used to build a website from Layout to Forms.

There is the more core components like `Typography`, `Container` and `Link`.

- `Typography` component which we have just used which has a whole range of variants that allow all headings & paragraphs.
- Layout components like `Box` and `Container` for building wrappers and containers.
- Interactive components like `Link` replace `<a />` tags

Then there are more bespoke components like `Breadcrumb` and `Paper`. These are prebuilt components that allow you to build the detail of your component more quickly in a uniform design language.

However if you find that there is a component that you need to build yourself, you are not just stuck with what is provided. There are also tools so that you can style your own components and create the styles for them.

## Making styles

Styling is done using `JSS`. It's like `CSS` but done with JavaScript objects and the JavaScript names for properties (`camelCase`).

### Styling child elements

We have created a theme and it can be used by the built in components, but what if we have some user generated content or there is some markup that you don't want to convert directly to use MUI components. This is where you can use styles.

Let's say we have the following:

```
const UserContent = () => {

    return (
        <div>
            <h3>I am a user comment</h3>
            <p>Here is a list:</p>
            <ul>
                <li>Point A</li>
                <li>Point 2</li>
                <li>Final point</li>
                <li>The end!</li>
            </ul>
        </div>
    )
}

export default UserContent;

```

![Unstyled user content](https://carl-topham.com/content/articles/react-material-ui-mui/usercontent-unstyled.png)

First we want to create some styles in the `UserContent` component:

```
import makeStyles from "@material-ui/core/styles/makeStyles";

// Takes the theme we have used in the ThemeProvider
const useStyles = makeStyles((theme) => ({
    userContentStyles : {
        // Create a catch all style for all elements so we don't
        // need to create each HTML element
        // we use the body1 property which is for <p />
        // the theme.typography.body1 is an object so this can be added straight on the key
        "& *": theme.typography.body1,
        // To style the <h3 /> we can create a style for it.
        "& h3": {
            // because we are using 2 properties in here we need to wrap them in braces. 
            // We also have to spread the typography object.
            ...theme.typography.h3,
            // Then we can just apply the color using the theme's color object which is a string.
            color: theme.palette.secondary.main
        },
        "& li": {
            // To apply some spacing to our list we could use some spacing properties
            marginBottom: theme.spacing(4)
        },
    }
}));
// ... rest

```

With the `h3` element we have to spread the typography object because it contains things like font-sizes, line-height, weight etc. When it is the only value we're using for a key (eg `& *`) you don't need to spread it!

If you wanted to pick only certain aspects of the h3 typography object you could just pull out the values you need.

```
"& h3": {
    fontWeight: theme.typography.body1.fontWeight, // pseudo code: Not sure these are the prop names!
    lineHeight: theme.typography.body1.lineHeight, // pseudo code: Not sure these are the prop names!
    // and so on!
}

```

With the palette properties we don't need to spread them because they are just a value so we can use it as is.

Now we can use the styles in the component itself.

```
const UserContent = () => {
    // Then we get the created styles in the component
    const styles = useStyles()

    // Add them as a className. Note we use the "userContentStyles" key of the styles object
    return (
        <div className={styles.userContentStyles}>
            <h3>I am a user comment</h3>
            <p>Here is a list:</p>
            <ul>
                <li>Point A</li>
                <li>Point 2</li>
                <li>Final point</li>
                <li>The end!</li>
            </ul>
        </div>
    )
}

export default UserContent;

```

![Styled user content](https://carl-topham.com/content/articles/react-material-ui-mui/usercontent-styled.png)

> Note: I am making very obvious changes for illustrative purposes. My UI skills are better than the above design!

### Classes for each element

The other way we can style child elements is using class names for all elements.

Make a new component `Classy/index.jsx`. First we import the `makeStyles` and use this to define a style function that uses the theme to return our styles.

```
import makeStyles from "@material-ui/core/styles/makeStyles";
 
 // Takes the theme we have used in the ThemeProvider
 const useStyles = makeStyles((theme) => ({
     // These keys will be used to define the classes for components/elements
    wrapper: {
        // set the properties using theme values
        padding: theme.spacing(1),
        background: theme.palette.secondary.light
    },
     heading: {
         color: theme.palette.secondary.contrastText,
         ...theme.typography.h4, // spread objects
     },
     content: {
        padding: theme.spacing(2),
         color: theme.palette.primary.contrastText,
         background: theme.palette.primary.dark,
         // We can also target nested children as per the other example
         "& *": theme.typography.body1,
     }
 }));
// ..rest

```

In the above example the `wrapper`, `heading` and `content` are all going to be propeties of the style object we create so we can then use them as our classes. We do this by creating the style object in the component as `styles` and then we can use `styles.PROPRTY_NAME` to use the className that the JSS/makeStyles has created for us, like so:

You should have noticed that we have mixed both classes on multiple components (`styles.WHATEVER`), and child component styling (`& *`). That gives us great flexibility to style what we need.

```
const Classy = () => {
    // Create the styles object
    const styles = useStyles()

    // Then use the keys we created above to apply the classes to the right elements
    return (
        <div className={styles.wrapper}>
            <h4 className={styles.heading}>I am styled by the "styles.heading".</h4>
            <div className={styles.content}>
                <p>Hello! 👋. This element is styled by the nested selector "& *".</p>
            </div>
        </div>
    )
}

export default Classy;

```

Import it into your `App.js` and add it to the component and you should see something like this:

![Styled components using JSS](https://carl-topham.com/content/articles/react-material-ui-mui/styles-jss.png)

That covers child components, but what about global elements!

## Global styles

So far we have seen how to style components and their descendants. But what about if you need to apply style to the `html` or `body`?

In this case you still create a component, however you can style [Global elements](https://material-ui.com/customization/components/#global-css-override) by creating a `@global` style. Anything within this is applied to the the root and becomes global. Within this you can add your selectors such as `body` and apply the styles you need.

> Note: By default, MUI already has [normalised styles](https://material-ui.com/components/css-baseline/) applied to elements to keep all browsers consistent.

```
import withStyles from "@material-ui/core/styles/withStyles";

const GlobalCss = withStyles({
    '@global': { // Declare a @global selector in order for jss to pull out the styles
        "html, body": { // create your styles to apply globally
            margin: 0,
            padding: 0,
            backgroundColor: "#pink"
        },
    },
})(() => null);

export default GlobalCss;

```

Then import and use it in your App:

```
import { ThemeProvider } from '@material-ui/styles';

import theme from "./theme";
import TitleBlock from "./Components/TitleBlock";
import UserContent from "./Components/UserContent";
import GlobalCss from "./Components/GlobalCSS";

const App = () => {
  return (
    <>
      <GlobalCss />
      <ThemeProvider theme={theme} >
          <TitleBlock title="Material UI Playground" />
          <UserContent />
      </ThemeProvider>
    </>
  );
}

export default App;

```

![Global themed](https://carl-topham.com/content/articles/react-material-ui-mui/mui-global-styled.png)

You can also create global styles for the MUI component classNames in the `GlobalCSS`.

```
const GlobalCss = withStyles({
    '@global': { // Declare a @global selector in order for jss to pull out the styles
        "html, body": { // create your styles to apply globally
            margin: 0,
            padding: 0,
            backgroundColor: "pink"
        },
        // Target the MUI class
        ".MuiTypography-h1": {
            textDecoration: "underline" // A silly style to make a point!
        }
    },
})(() => null);

export default GlobalCss;

```

![silly point](https://carl-topham.com/content/articles/react-material-ui-mui/silly-point.png)

### Nested themes

With nested themes you need to target classes via the more generic `[class*="MuiTypography-h1"]` if you wish to style all of an element.

> The `[class*="CLASSNAME"]` selector selects all classes that contain a value of `CLASSNAME`.

We need to use this because the nested theme class names change from `MuiTypography-h1` to `MuiTypography-h1-9999` where `9999` is a unique theme number! We are selecting all classes that contains `MuiTypography-h1`.

```
const GlobalCss = withStyles({
    '@global': {
        // ... the rest
        ".MuiTypography-h1": { // only targets the to level / single theme
            textDecoration: "underline"
        },
        '[class*="MuiTypography-h1"]': { // Targets all themes due to selector
            fontSize: "1em"
        }
    },
})(() => null);

```

I am using the same theme twice just to demo the class name changes, but you would use a secondary theme in the real world™️!

```
<ThemeProvider theme={theme} > // Top level theme
  <TitleBlock title="Material UI Playground" /> // uses only top level theme
  <ThemeProvider theme={theme} > // Nested theme
      <TitleBlock title="Material UI extra themed" /> // Uses nested theme overides and top level theme
      <UserContent />
  </ThemeProvider>
</ThemeProvider>

```

![Nested theme overrides](https://carl-topham.com/content/articles/react-material-ui-mui/themeGlobal.png)

## The end!

And there you have it. You can now style everything from the built in components, through to nested child components and global styles too.