PsyGik
PsyGik

Reputation: 3675

React + Material UI - Overriding MuiTheme in component withStyles

I am using Material UI with React. Trying to override the TextField component style which has been setup using a global theme. I have setup a global theme for all TextField components in the app.

Relevant code:

theme-engine.js:

export const theme = brand => createMuiTheme({
    palette: {
        primary: {
            main: Brand.getColors(brand).primary
        },
        secondary: {
            main: Brand.getColors(brand).secondary
        },
    },
    typography: {
        fontFamily,
        fontSize: 14,
        htmlFontSize: 16
    },
    overrides: {
        MuiInputBase: {
            root: {
                color: 'rgba(0, 0, 0, 0.87)',
                fontSize: '14px',
                fontFamily,
                '&:after': {
                    borderBottom: Brand.getColors(brand).primary,
                    backgroundColor: Brand.getColors(brand).primary,
                    height: 1
                },
                '&:focused:not($disabled):not($error):before': {
                    borderBottom: Brand.getColors(brand).primary,
                    backgroundColor: Brand.getColors(brand).primary,
                    height: 1
                },
                '&$error:before': {
                    borderBottom: '#f44336',
                    backgroundColor: '#f44336',
                    height: 1
                },
            },
        },
        MuiInput: {
            root: {
                fontFamily
            },
            underline: {
                '&:hover:not($disabled):not($error):not($focused):before': {
                    borderBottom: '#e0e0e0',
                    backgroundColor: '#e0e0e0',
                    height: 1
                },
                '&:not($disabled):not($error):after': {
                    borderBottom: Brand.getColors(brand).primary,
                    backgroundColor: Brand.getColors(brand).primary,
                    height: 1
                },
                '&$error:before': {
                    borderBottom: '#f44336',
                    backgroundColor: '#f44336',
                    height: 1
                },
                '&$error:after': {
                    borderBottom: '#f44336',
                    backgroundColor: '#f44336',
                    height: 1
                },
            },
        },
        MuiSvgIcon: {
            colorPrimary: {
                fill: '#74797b'
            },
            colorSecondary: {
                fill: Brand.getColors(brand).primary,
            }
        },
    }
});

container.js:

 render() {
        return (
            <MuiThemeProvider theme={theme(brand)}>
                //stuff goes here
            </MuiThemeProvider>
        )
    }

Now in one of the components, I am using an icon for the TextField and want the underline to come under the icon as well. For that I am trying to override the provided theme, which isn't working. The styles from the theme-engine are applied, but the local override isn't working.

some-component.js

import TextField from '@material-ui/core/TextField';
import {withStyles} from '@material-ui/core/styles';
const TextFieldIcon = withStyles(theme => ({
    root: {
        underline: {
            color: 'red',
            height: 4,
            '&:before': {
                borderBottom: `1px solid #e0e0e0`,
                bottom: '-8px',
                left: '-32px'
            },
            '&:hover:not($disabled):not($error):not($focused):before': {
                borderBottom: 'red',
                backgroundColor: 'red',
                height: 1,
                bottom: '-8px',
                left: '-32px'
            },
            '&:not($disabled):not($error):after': {
                height: 2,
                bottom: '-8px',
                left: '-32px'
            },
            '&$error:before': {
                height: 1,
                bottom: '-8px',
                left: '-32px'
            },
            '&$error:after': {
                height: 1,
                bottom: '-8px',
                left: '-32px'
            },
        },
    }
}))(TextField);

class SomeComponent extends Component{
        //Lifecycle methods to make your life easier....or difficult.

        render(){
            return(
                <TextFieldIcon {...assign props and stuff} /> //Styles are not applied
            )
        }
}

So the question is, I want to keep the custom global theme, but also override some parts of it in my component. Any inputs appreciated.

Upvotes: 1

Views: 3325

Answers (1)

Ryan Cogswell
Ryan Cogswell

Reputation: 80986

I see a few issues:

  • You should not have the underline rule nested under root. You should be able to just remove the outer root block
  • In order to refer to other rules (e.g. $disabled, $error, and $focused), those rules need to be defined within the styles object you pass to withStyles
  • The classes generated by withStyles are the classes for the Input component wrapped by TextField, so you need to pass them via the InputProps property

Below is a working example of the syntax you need. I have not tried to assess whether the styles are doing what you intend, but they are definitely being applied.

import React from "react";

import TextField from "@material-ui/core/TextField";
import { withStyles } from "@material-ui/core/styles";
const styles = theme => ({
  underline: {
    color: "red",
    height: 4,
    "&:before": {
      borderBottom: `1px solid #e0e0e0`,
      bottom: "-8px",
      left: "-32px"
    },
    "&:hover:not($disabled):not($error):not($focused):before": {
      borderBottom: "red",
      backgroundColor: "red",
      height: 1,
      bottom: "-8px",
      left: "-32px"
    },
    "&:not($disabled):not($error):after": {
      height: 2,
      bottom: "-8px",
      left: "-32px"
    },
    "&$error:before": {
      height: 1,
      bottom: "-8px",
      left: "-32px"
    },
    "&$error:after": {
      height: 1,
      bottom: "-8px",
      left: "-32px"
    }
  },
  disabled: {},
  error: {},
  focused: {}
});
const CustomTextField = ({ classes, ...other }) => {
  return <TextField InputProps={{ classes: classes }} {...other} />;
};

export default withStyles(styles)(CustomTextField);

Edit Custom TextField

Upvotes: 1

Related Questions