Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 97 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save Danilo-Araujo-Silva/2ce11fd0540dcc7eb3ad3e67fd75d02a to your computer and use it in GitHub Desktop.
Save Danilo-Araujo-Silva/2ce11fd0540dcc7eb3ad3e67fd75d02a to your computer and use it in GitHub Desktop.

For example, to override the AppBar (https://material-ui-next.com/api/app-bar/) root class we can do the following:

First method (override Material UI classnames):

1 - Add the property classes in the AppBar component:

    <AppBar classes={{root: 'my-root-class'}}

2 - Override the styles with the styled components:

    styled(AppBar)`
      &.my-root-class {
        z-index: 1500;
      }
    `

Second method (force specificity):

    styled(AppBar)`
      && {
        z-index: 1500;
      }
    `

Third method (use a custom classname):

1 - Add the classname in the classname property:

    <AppBar className={`my-class ${this.props.otherClassesFromPropertiesIfNeeded}`}

2 - Override the styles with the styled components:

    styled(AppBar)`
      &.my-class {
        z-index: 1500;
      }
    `

Fourth method (use a custom classname generator)

You can control the classenames that will be generated by MaterialUI. Maybe it will require a little more effort but it can also bring more flexibility.

Please see these sections of the documentation:

/path/to/the/theme/provider/ThemeProvider.js:

import React from "react"
import MuiThemeProvider from "material-ui/styles/MuiThemeProvider"
import {createGenerateClassName} from "material-ui/styles"
import JssProvider from "react-jss/lib/JssProvider"

import {yourTheme} from "/path/to/your/theme"

const generateClassName = createGenerateClassName({
  dangerouslyUseGlobalCSS: true,
  productionPrefix: 'mui',
})

const ClassNameGenerator = (p) =>
  <JssProvider generateClassName={generateClassName} {...p}>
    {p.children}
  </JssProvider>

export class ThemeProvider {

  render() {
    return (
      <ClassNameGenerator>
        <MuiThemeProvider theme={yourTheme}>
          {this.props.children}
        </MuiThemeProvider>
      </ClassNameGenerator>
    )
  }
}

/path/to/the/root/component/Root.js

import React from "react"
import {Provider} from "react-redux"

import {ThemeProvider} from "/path/to/the/theme/provider/ThemeProvider"
import {Router} from "/path/to/your/router/definitions/Router"
import {reduxStore} from "/path/to/your/redux/store"

export class Root {

  render() {
    return (
      <Provider store={reduxStore}>
        <ThemeProvider>
          <Router />
        </ThemeProvider>
      </Provider>
    )
  }
}
@leoyli
Copy link

leoyli commented Feb 14, 2019

Although a bit dirty, here is my version to enforce the specificity at the very first place (logic can be wrapped in a component so React can pick it up):

  const setBeforeRepaint = 'requestAnimationFrame' in window ? requestAnimationFrame : setTimeout;
  setBeforeRepaint(() => {
    const styledComponents = document.querySelector('style[data-styled]');
    if (styledComponents) {
      styledComponents.parentNode.append(styledComponents);
    }
  });

This ensure CSS injected by the styled-components will always win, and it only need to be exercise once and before browser start to paint the next frame.

@JimVanEeden
Copy link

JimVanEeden commented Jun 5, 2019

In material-ui v4, you can simply do:

import { StylesProvider } from '@material-ui/styles';
// [other imports]

// [code]

function App() {
    return (
        <StylesProvider injectFirst> // this
            <MuiThemeProvider theme={theme}
                <Routes />
            </MuiThemeProvider>
        </StylesProvider>
    );
}

Took me a bit to find it, because it's not in the migration guide. The original technique as described above doesn't work anymore in v4. Hope this helps somebody else.

@mikew
Copy link

mikew commented Jul 25, 2019

What if you need to pass the class name down deeper, like to InputProps.className, from TextField?

@panuavakul
Copy link

@mikew Did you figure it out? I'm also looking for the solution to the same answer.

@shilangyu
Copy link

@JimVanEeden you saved my life, first time seeing this solution. Where did you find that? Its the simplest yet not in the docs

@JimVanEeden
Copy link

@shilangyu I can't remember honestly :'). I think I just looked through the source or something.

@DylanSp
Copy link

DylanSp commented Aug 26, 2019

@JimVanEeden Thanks a ton for that solution! It makes things a lot easier.

@shilangyu It's in the docs, in the Advanced section under Styles.

@TomPfundt
Copy link

@JimVanEeden Thanks, thats exactly what I've been looking for, just wish I found it an hour or two ago!

@sladg
Copy link

sladg commented Dec 23, 2019

In material-ui v4, you can simply do:

import { StylesProvider } from '@material-ui/styles';
// [other imports]

// [code]

function App() {
    return (
        <StylesProvider injectFirst> // this
            <MuiThemeProvider theme={theme}
                <Routes />
            </MuiThemeProvider>
        </StylesProvider>
    );
}

Took me a bit to find it, because it's not in the migration guide. The original technique as described above doesn't work anymore in v4. Hope this helps somebody else.

Thx! It worked!

import { StylesProvider } from '@material-ui/styles';
import App from 'next/app';
import React from 'react';
import { ThemeProvider } from 'styled-components';

const theme = {
  colors: {
    primary: '#037Ef3',
    textLight: '#F3F4F7',
  },
};

class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;
    return (
      <StylesProvider injectFirst>
        <ThemeProvider theme={theme}>
          <Component {...pageProps} />
        </ThemeProvider>
      </StylesProvider>
    );
  }
}

export default MyApp;

@wasinsandiego
Copy link

@mikew @panuavakul
You can use the typical sass-like nested selectors. Selector as keys and value as object with css properties.

Only thing you need to know is the class names you want to target. If you render the input you can inspect and see the class names of the element you want to target. There may also be some info in the docs, but I haven't noticed it.

For the MUI within TextField I can see these class names on the input.

.MuiInputBase-input
.MuiInput-input

Here's an example.

Notice the empty space between the & and the class name.

const Search = styled(TextInput)({
  width: '100%',
  marginBottom: '15px',
  background: '#fff',
  '& .MuiInputBase-input': {
    background: '#ff00ff',
    color: '#fff',
    fontWeight: '900',
  },
})

If you need more specificity it's best to simply chain more class names.

const Search = styled(TextInput)({
  width: '100%',
  '& input.MuiInputBase-input.MuiInput-input': {
    background: '#ff00ff',
  },
})

@garyanikin
Copy link

Easiest way https://material-ui.com/ru/guides/interoperability/#styled-components
To provide injectFirst property to StylesProvider component

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

<StylesProvider injectFirst>
  {/* Your component tree.
      Now, you can override Material-UI's styles. */}
</StylesProvider>

@avxkim
Copy link

avxkim commented Apr 23, 2020

All the above mentioned methods are ugly, if you want to pass classes object, just do it this way:

const ModifiedAppBar = styled(({...rest}) => (
  <AppBar classes={{root: 'my-root-class'}} {...rest}/>
))`
  .my-root-class {
    z-index: 1500;
  }  
`

@shilangyu
Copy link

All the above mentioned methods are ugly, if you want to pass classes object, just do it this way:

const ModifiedAppBar = styled(({...rest}) => (
  <AppBar classes={{root: 'my-root-class'}} {...rest}/>
))`
  .my-root-class {
    z-index: 1500;
  }  
`

this is literally what the gist is proposing as a solution

@juanbelieni
Copy link

@JimVanEeden Thank you, it worked.

@adamhenson
Copy link

adamhenson commented Aug 11, 2020

In material-ui v4, you can simply do:

import { StylesProvider } from '@material-ui/styles';
// [other imports]

// [code]

function App() {
    return (
        <StylesProvider injectFirst> // this
            <MuiThemeProvider theme={theme}
                <Routes />
            </MuiThemeProvider>
        </StylesProvider>
    );
}

Took me a bit to find it, because it's not in the migration guide. The original technique as described above doesn't work anymore in v4. Hope this helps somebody else.

When I use this "solution", I see a flickering of styles in the browser. I'm guessing styles are moved in the DOM client-side (not server-side). For me this is a deal-breaker. Would anyone know if I'm missing something else?

@lukestewart13
Copy link

Just want to post a thanks here man. Thank you.

@idembele70
Copy link

Man i just take a Minute to say you thanks and god bless you since months i was trying to find a clever solution to this problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment