How to Override Material UI Default Styling When All Else Fails

Anyone using Material UI has been there: you tried every trick and yet Material UI default styling is overriding your custom styling. This happens with padding, margin, colors, and more. Worry no more, I’m about to give you the Material UI bazooka. (If you haven’t tried every trick in the book, then simply start with the className property).

There are two different options to choose from if you are in a pinch. You can override the component using withStyles, or you can use inline styling. Both work and both are recommend options in the Material UI styling docs. Inline styling is likely the simpler option, but some developers prefer not to use inline styles as a rule.

Create a New Component using withStyles

Impossible to add margin?

Material UI TextField components are a prime example of the challenge of MUI styling. Let’s attempt to add margin around the above TextFields. If you target the root class on each TextField, you’ll get a nasty surprise during the prod build: the custom styling gets removed and margin: 0px is applied.

Why does this happen? It’s because MUI uses a formula of Component + Class to understand what class is being overridden. For TextField root class, we target the root class in the following way, expecting to be able to override the default margin:

<TextField variant='outlined' label='Text Field 1' classes={{ root: classes.textFieldRoot }} />

This will override MUI’s dynamically created class, MuiTextField-root. The problem is that margin is being set by a different class: MuiFormControl-root.

We don’t have a way to target the MuiFormControl-root class for an override when we are working with a TextField component. Instead, we override the component’s styling using withStyles and create a new component (learn more about withStyles here).

import React, { FC, useMemo } from 'react';
import { TextField, withStyles } from '@material-ui/core';
import { useStyles } from './form.styles';

export const Form: FC = () => {
    const classes = useStyles();
    const StyledTextField = useMemo(
        () => {
            return withStyles({
                root: {
                    margin: 8
                }
            })(TextField);
        }, []
    );

    return <form>
        <StyledTextField variant='outlined' label='Text Field 1' />
        <StyledTextField variant='outlined' label='Text Field 2' />
    </form>
}

If the StyledTextField is created in a separate file and imported, useMemo won’t be needed. However, if the StyledTextField is created as in the above gist, useMemo is essential. If you don’t memoize the component, you will encounter a bug where the StyledTextField loses focus with every onChange. This is because each onChange triggers a re-render of the parent component, thus creating a new StyledTextField and seemingly losing focus.

Here’s an example of a style Typography component being used.

Read the docs here: https://material-ui.com/customization/components/

Inline Styling

A simpler approach than creating a new component is to use inline styling. This is as simple as the following:

<TextField style={{ margin: 8 }} variant='outlined' label='Text Field 1' />

Use inline styling judiciously, or perhaps never.

Keep both of these options in your toolbox, and Material UI will be more flexible and less frustrating for your future endeavors.

There are more examples of styling TextField on this site here and here, but if you want to gain an in-depth understanding of Material-UI syntax and APIs for styling components, I recommend you read my book, Styling Material-UI Components. I cover the class object API, Styled Components, and overriding components using the theme. Furthermore, there are many more examples of custom component styling.

Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.