Start Customizing Material UI Like a Pro: Beginner's Guide
Tags: webdev, react
Published: 2023-04-01 03:37:19

Nowadays, [Material UI](https://mui.com/) is one of the most popular UI libraries for React. By installing the library, developers can introduce [Material Design System](https://m3.material.io/) onto their web pages without some tedious effort.

For example, adding a text field and a button is as easy as:
```jsx
import { Box, Button, TextField } from "@mui/material";
```
Then using it as:
```jsx
<Box>
    <TextField label="name" variant="standard" />
    <Button variant="contained">Submit</Button>
</Box>
```
Output:

![material-design text field and button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bny4q687cmcnx16duzz7.png)

However, despite having excellent documentation, further customizing Material UI components to fit a company's branding is not trivial. Due to this, web developers new to Material UI may find the library overwhelming. This blog post will briefly address some difficulties a developer may face when getting started with the library. While doing this, we will also go over a quick example to customize a Material UI `TextField` component.

> Note: This post is a quick start guide for developers new to Material UI. It is NOT documentation for Material UI. For the official documentation, please refer to [Material UI's official website](https://mui.com/). In addition, the post is written when Material UI v5 is the latest stable version. Please consider the timeliness of information when reading this blog post.

## How to Style?

There are so many ways to style with Material UI. The library gives enough freedom to developers, so you can choose how to style your web page based on your circumstances.

### Stying with Styling Libraries
If you are familiar with other styling libraries, such as [Styled Components](https://styled-components.com/), [Tailwind CSS](https://tailwindcss.com/), or [Emotion](https://emotion.sh/docs/introduction), Material UI has good support for these styling engines. You can start using these libraries by installing them normally.

After installing your preferred styling library, please keep an eye on the `<style>` tags under the `<head>` of your page. We can utilize the "inspect elements" feature on the browser and take a look:


![html style tags from "inspect element" feature of a browser, showing styles injected by material ui library](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyt4ixanw2q6uehw76in.png)

The style tags in the image above are injected by Material UI. Depending on your styling library, if Material UI injects styles _after_ your chosen styling library, some of your custom styles might be overridden unexpectedly.

This is one of the most common problems that developers may encounter with Material UI. To make it even worse, there is no checker in place to log error messages or warnings. Therefore, it is important to realize the CSS injection order and make corrections before we continue.

Assuming in our `index.js` file, we have:

```jsx
import { App } from "./App";

const root = ReactDOM.createRoot(
  document.getElementById("root")
);
```

To correct the injection order, we can utilize the `StyledEngineProvider` component exported by Material UI, as follows:

```jsx
import { StyledEngineProvider } from "@mui/material";

// ...

root.render(
  <StyledEngineProvider injectFirst>
    <App />
  </StyledEngineProvider>
)
```

This will fix the injection order, allowing the Material UI styles to appear first in the `<head>` section, followed by your custom styles.

### Styling with Plain CSS

If you are looking for the traditional approach, you may also style with plain CSS. Just add a class name to your component and style it with a CSS file.

Example.style.css
```css
.button {
  background-color: #000;
}
```

Example.jsx
```jsx
import "./Example.style.css";

export const Example = () => {
  return (
    <Box>
      <TextField label="name" variant="standard" />
      <Button variant="contained" className="button">
        Submit
      </Button>
    </Box>
  )
}
```

Output:

![example web page with a black background button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/biy1tyi2f3nu2mvcjar2.png)

### Styling with Material UI Systems

In addition to the two methods above, you can add some quick styles with helpers exported by Material UI. Some people prefer this method more than the previous ones, as it may be the most intuitive for one to work with all Material UI features.

Each component exported by Material UI accepts an `sx` prop. You can add custom CSS here, as follows:

```jsx
<Box>
  <TextField label="name" variant="standard" />
  <Button variant="contained" sx={{ backgroundColor: "#000" }}>
    Submit
  </Button>
</Box>
```

This will produce the same effect as in the plain CSS section.

The `sx` prop allows more features, such as accessing the global `theme` element that you may configure with `ThemeProvider` exported by Material UI. [Read more about themes in the Material UI official documentation](https://mui.com/material-ui/customization/theming/).

```jsx
<Box sx={{ margin: 16, padding: 8 }}>
  <TextField label="name" variant="standard" />
  <Button
    variant="contained"
    sx={{
      backgroundColor: "#000",
      marginLeft: (theme) => theme.spacing(2),
    }}
  >
    Submit
  </Button>
</Box>
```

Output:


![text field and button with left margin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y7wp8c1eusa5fp8p1u7e.png)

Note the left margin of the button.

In fact, even the `Box` element that we are using up to this point is part of the "Material UI System" components. "Box" is a wrapper component for styling purposes, while one can also use other components such as "Container", "Grid", or "Stack" to produce complex layouts. For example,

```jsx
<Stack spacing={2}>
  <TextField label="name" variant="standard" />
  <Button variant="contained">Submit</Button>
</Stack>
```

Output:

![Stacked text field and button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qs1j3youp90cfd1ejjfi.png)

Learn more about Material UI System here: [Official MUI Documentation](https://mui.com/system/getting-started/overview/).

### Styling with "makeStyles"

If you are a developer migrating from Material UI v4, you may ask, "how about styling with `makeStyles` and `useStyles`?" While these utilities are deprecated in Material UI v5 and won't work unless you install deprecated packages, we can always make these utility functions ourselves.

```
const useStyles = () => ({
  button: {
    backgroundColor: "#000",
  },
});
```

and remember the `sx` prop that we introduced above? We can still do `classes = useStyles();`, then assign `classes.button` to the `sx` prop.

## Example: Customizing Text Field

Styling work in the real world often needs to match a branding guideline, so it will be more complicated than just using Material UI out of the box. Suppose that we want to have a text field that looks like the following:


![states of a customized text field](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2hnvr5il2a13e9xp5zf.png)

Of course, looking at all variants of the Material UI text field, it is quite different:

![material ui: variants of text fields](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6iwpmq8ozxd5ke87z3ir.png)

In general, we follow the following steps when customizing a Material UI component:

1. Determine the scope of the customization;
2. Determine the component states/classes that will be affected;
3. Complete the customization

### Determine the scope of the customization

First, we need to understand the scope of our customization. Depending on the answer, one might choose to solve the customization using one of the following methods:

i. Styling from the ground up using the base package. Material UI has a [base package](https://mui.com/base/getting-started/overview/), which hosts the "unstyled" MUI components. This is beyond the scope of this blog post;
ii. Expanding a Material UI component to access the lower-level components. For example, the Material UI `TextField` component is an abstraction of `FormControl`, `InputLabel`, `FilledInput`, `OutlinedInput`, `Input`, and `FormHelperText` (Source: [Material UI Text Field API Docs](https://mui.com/material-ui/api/text-field/#advanced-configuration)).
iii. Styling directly on the component using properties and class names accessible.

In our case, we can style directly on the `TextField` component.

### Determine the component states/classes that will be affected

We will customize the hover state and the `focused` state of the text field. Note that Material UI generates a list of [global CSS class names](https://mui.com/system/styles/advanced/#class-names). For the focused state, we should customize using the `.Mui-focused` class.

### Complete the customization

We will base our customization off a [Filled Input](https://mui.com/material-ui/api/filled-input/).

CustomizedTextField.jsx

We start by adding some styles for the text field.
```jsx
const getRootStyles = (theme) => ({
  "& .MuiFilledInput-root": {
    border: `1px solid ${theme.palette.grey["A200"]}`,
    overflow: "hidden",
    borderRadius: theme.spacing(0.5),
    transition: theme.transitions.create([
      "border-color",
      "background-color",
      "box-shadow",
    ]),
    "&:hover": {
      backgroundColor: "transparent",
    },
    "&.Mui-focused": {
      backgroundColor: "transparent",
      borderColor: theme.palette.primary.main,
    },
  },
});
```

Note that we are using the `theme` object. The `theme` object is managed the the Material UI library, and we can get `theme` by calling the hook `useTheme`. `useTheme` is exported by "@mui/material".

```jsx
const CustomizedTextField = (props) => {
  const theme = useTheme();
  const root = getRootStyles();
  const { sx, InputProps, ...otherProps } = props;

  return (
    <TextField
      variant="filled"
      InputProps={{ disableUnderline: true, ...InputProps }}
      sx={{ ...root, ...sx }}
      {...otherProps}
    />
  );
};
```

and finally
```jsx
export { CustomizedTextField }
```

If you wonder where we get class names such as `.MuiFilledInput-root`, we can get them by using the official documentation or the "inspect element" function in your browser.

We can now import `CustomizedTextField` from `CustomizedTextField.jsx` and start using it.

The icon at the end of the text field came from the `inputAdornment` prop. One can specify the input adornment when they use the custom component that we just exported. For example,

```jsx
import { InputAdornment } from "@mui/material"
import { Badge } from "@mui/icons-material";
import { CustomizedTextField } from "./CustomizedTextField"
```

```jsx
<CustomizedTextField
  label="name"
  InputProps={{
    endAdornment: (
      <InputAdornment position="end">
        <Badge style={{ color: "#C3C3C3" }} />
      </InputAdornment>
    ),
  }}
/>
```

We're all set! We have now completed the custom text field that we wanted at the beginning of this section.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a8mkfxbllok7ye4e0y4t.png)

 
## Final Words

I hope this blog post is helpful for your Material UI journey. Thank you for your time checking out my post!