9.1 React Design

# MUI (Material-UI)

As we started talking about last week, MUI is a great system for building and styling your React Apps. Used in conjunction with the emotion library (opens new window) styling system, it comes with lots of great pre-built components, styling methods, palettes, colours, hooks, and themes.

It is a large system with a lot of different elements to use but the best part is that it can be used incrementally. Not everything in your app has to be an MUI Component. And you can use your own CSS files and classes in combination with MUI.

It is important to note that we are using version 5 of MUI. Versions 1 through 4 were called Material-UI. They had a different domain, a different package name and all the imports were in different folders.

The simplest swap is for the component imports.

//v4
import Button from '@material-ui/core/Button';
//v5
import Button from '@mui/material/Button';
1
2
3
4

Note the change of the first two parts of the import path. This change is the same for ALL components.

All the version 5 imports will start with @mui/. Most of them start with @mui/material. We will see a couple others below but the differences will be highlighted in the example.

# MUI Components

Here is the list of supported components in MUI (opens new window). On the MUI site, to reference the Components and see examples of all the variants, be sure to go to the Components section of the menu. This list is grouped by purpose type.

If you are just looking for the list of attributes/properties that you can add to a Component, then go to the Component API section of the left-hand menu.

Components are meant to be used in place of the html-style JSX elements that you write in your React applications.

A few guidelines:

  • If you want to add some text, use a <Typography> component.
  • If you want a div-like container, use a <Box> component.
  • Some components, like <Button variant="contained" startIcon={<DeleteIcon/>}>Delete</Button> have properties that let you load another component inside them.
  • Material Icon Font is a font used for the icons. This means all CSS font properties like size and color apply to the icons.

The search tool on the MUI website is an excellent way to navigate the huge amount of resources on their site.

# MUI Styling

The styled() method can be imported from @mui/material.

import { styled } from '@mui/system';
1

It is a great way to build a styled version of a Component for your current page. It builds on top of the default theme from MUI or on top of a theme object that you create yourself. Styled reference page (opens new window)

//method signature
styled(Component, [options])(styles) => Component
1
2

From the method signature we can see that styled() accepts a base Component (along with its theme styling) and an optional options object. It returns a function that gets called and passed a styles object. It returns your new styled Component.

It is worth noting that this is NOT the only way of styling components. There is also:

  • the sx prop, which will be discussed in the theming section.
  • the style tagged template literal approach from emotion.
  • styled-component which is part of the alternate import shown in the first MUI content in week 7.

Here is a simple example of the method being used to build a styled div.

const CustomDiv = styled('div')({
  color: 'darkslategray',
  backgroundColor: 'aliceblue',
  padding: 8,
  borderRadius: 4,
});

export default function MyComponent() {
  return (
    <main>
      <CustomDiv>Styled div</CustomDiv>
    </main>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# MUI Themes

MUI comes with a default theme, which is a collection of a range of CSS properties intended to style all the components. You can also use these theme values to style your own components.

# Theme Provider

Themes use React Context to work. This means that we need to create a Theme Provider and put that up near the top level of our app. Note the import path.

import { createTheme, ThemeProvider } from '@mui/system';
1

This will give use the ThemeProvider component to put in our JSX.

export default function App() {
  return (
    <ThemeProvider theme={myTheme}>
      <SomeAppStuffAndMyOtherComponents />
    </ThemeProvider>
  );
}
1
2
3
4
5
6
7

The ThemeProvider has a theme property that needs to be given a theme object. We use the createTheme method to create the theme object to pass into the Provider.

//outside the App function
const myTheme = createTheme({
  palette: {
    primary: {
      main: '#123abc',
      contrastText: '#eee',
    },
  },
});
1
2
3
4
5
6
7
8
9

The default Theme is passed in and merged with the theme object we are creating. See the default theme here (opens new window).

Now your theme will be stored as a Context that we can access from other files (Components).

# useTheme Hook

To access the custom theme from inside any other page/file/component we need to import the useTheme hook.

import { useTheme } from '@mui/material/styles';

export default function MyThing() {
  const theme = useTheme();
  console.log(theme); //see the theme object
  //we can extract values from the theme.

  return (
    <div>
      <h1>{theme.spacing}</h1>
      <h2>{theme.palette.mode}</h2>
      <h3>{theme.palette.primary.main}</h3>
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Theme with styled()

We can access the values from the custom theme when using the styled method too. The example below will be passed an object and the theme object get destructured from that. Then in the styles object we are creating we can access the values from the theme, like theme.palette.primary.main.

const MyThemeComponent = styled('div')(({ theme }) => ({
  color: theme.palette.primary.contrastText,
  backgroundColor: theme.palette.primary.main,
  padding: theme.spacing(1),
  borderRadius: theme.shape.borderRadius,
}));
1
2
3
4
5
6

# The sx prop

With your MUI Components you can use the sx prop to set the values for various style properties. These will override the default values from MUI. For most elements you will have to add the colours and amount of spacing/padding you want to use.

See the sx prop reference (opens new window) in the System section of the left hand menu.

The sx prop accepts an object with style properties and values. the values are strings or numbers. Many of the strings are references to values inside the theme. This works even without the useTheme hook in your component.

<Typography
  sx={{
    color: 'success.dark',
    display: 'inline',
    fontWeight: 'medium',
    fontSize: 3
    px: 1,
  }}
>
1
2
3
4
5
6
7
8
9

In the above example, the color property accepts success.dark as the value. This is a shortcut to theme.palette.success.dark. The color property is mapped to look inside theme.palette. The fontWeight property is using the string medium which refers to the value in theme.typography.fontWeightMedium. The fontSize property is using the number 3. This is actually referencing an array index. In the theme being used for this example the theme.typography.fontSize value is an array with a type scale. [12, 14, 20, 24, 36, 48]. So the Typography component is going to use 20px as the font size. If, in your theme you have a single value saved as the fontSize then that will be used by default. The px value is also pointing to an array index.

Padding and margin can be referenced through m, mx, my, mt, mb, mr, ml, p, px, py, pt, pb, pr, or pl. Which refer to margin or padding on all sides, in the x direction, y direction, top, bottom, right or left.

# Spacing in a Theme

Some Components have a spacing prop that you can use to set the space between child components. The Grid Component (opens new window) is an example of an element using the spacing prop.

When creating your theme object, the value for spacing can be a number or a function. The default is the number 8. So, when you use the spacing prop in your component it will be your value multiplied by 8px.

You can override that recommended default value like this:

const theme = createTheme({
  spacing: 6,
});
1
2
3

Or you can set the value of spacing as a function to calculate the value.

const theme = createTheme({
  spacing: (factor) => `${0.5 * factor}rem`,
});
1
2
3

The value of factor is coming from your spacing prop. It will be multiplied by 0.5 and set as an rem value for the component.

OR alternatively you can pass in an array of values. Then the value in the spacing prop will be used as an array index.

Spacing Reference (opens new window)

Last Updated: : 10/29/2021, 3:56:47 PM