7
votes

I need to customize the material-ui autocomplete control so it's not so tall. I found a sample that works well to change the MuiOutlinedInput outline color using createMuiTheme on the Autocomplete's TextField. The codesandbox is here: Code Example

This is my theme override code and I added an override for the padding of the input class:

const theme = createMuiTheme({
  overrides: {
    MuiOutlinedInput: {
      root: {
        "& $notchedOutline": {
          borderColor: "green"
        },
        "&:hover $notchedOutline": {
          borderColor: "red"
        },
        "&$focused $notchedOutline": {
          borderColor: "purple"
        },
        "& $input": {
          padding: "1px"
        }
      }
    }
  }
});

And this is the component code:

 <Autocomplete
  id="country-select-demo"
  style={{ width: 300 }}
  options={countries}
  getOptionLabel={option => option.label}
  renderInput={params => (
    <MuiThemeProvider theme={theme}>
      <TextField {...params} label={"Countries"} variant="outlined" />
    </MuiThemeProvider>
  )}
/>

The problem is my padding for the input class gets overridden by this:

.MuiAutocomplete-inputRoot[class*="MuiOutlinedInput-root"] .MuiAutocomplete-input

Anything I can do to make my customization not get overridden by the above? I'm also open to other techniques other than createMuiTheme, or perhaps styling other parts of the autocomplete. I just need to make it not so tall.

Thanks!

1

1 Answers

13
votes

This is a matter of getting the appropriate CSS specificity for your override. One easy way to increase the specificity is to repeat a class.

In the example below, I use &&& $input which is equivalent to having .MuiOutlinedInput-root.MuiOutlinedInput-root.MuiOutlinedInput-root .MuiOutlinedInput-input:

const theme = createTheme({
  overrides: {
    MuiInputLabel: {
      outlined: {
        transform: "translate(14px, 12.5px) scale(1)"
      }
    },
    MuiOutlinedInput: {
      root: {
        "& $notchedOutline": {
          borderColor: "green"
        },
        "&:hover $notchedOutline": {
          borderColor: "red"
        },
        "&$focused $notchedOutline": {
          borderColor: "purple"
        },
        "&&& $input": {
          padding: "1px"
        }
      }
    }
  }
});

Edit Increase override specificity

Another option which is a bit uglier, but makes it more obvious which default styling you are overriding is the following:

const theme = createTheme({
  overrides: {
    MuiInputLabel: {
      outlined: {
        ".MuiAutocomplete-root &:not(.MuiInputLabel-shrink)": {
          transform: "translate(14px, 12.5px) scale(1)"
        }
      }
    },
    MuiOutlinedInput: {
      root: {
        "& $notchedOutline": {
          borderColor: "green"
        },
        "&:hover $notchedOutline": {
          borderColor: "red"
        },
        "&$focused $notchedOutline": {
          borderColor: "purple"
        }
      }
    },
    MuiAutocomplete: {
      inputRoot: {
        '&&[class*="MuiOutlinedInput-root"] $input': {
          padding: 1
        }
      }
    }
  }
});

Edit Increase override specificity (forked)

Notice that you still need to double the & in order to get specificity that wins over the default styles. This version is specific to auto complete rather than impacting all outlined inputs.

If you don't want to apply this override to the whole application in your theme, you can just customize the Autocomplete component using withStyles like the following:

import React from "react";
import TextField from "@material-ui/core/TextField";
import Autocomplete from "@material-ui/lab/Autocomplete";
import { withStyles } from "@material-ui/core/styles";

const NoPaddingAutocomplete = withStyles({
  inputRoot: {
    '&&[class*="MuiOutlinedInput-root"] $input': {
      padding: 1
    },
    "& .MuiOutlinedInput-notchedOutline": {
      borderColor: "green"
    },
    "&:hover .MuiOutlinedInput-notchedOutline": {
      borderColor: "red"
    },
    "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
      borderColor: "purple"
    }
  },
  input: {}
})(Autocomplete);
export default function CountrySelect() {
  return (
    <NoPaddingAutocomplete
      id="country-select-demo"
      style={{ width: 300 }}
      options={countries}
      getOptionLabel={option => option.label}
      renderInput={params => (
        <TextField {...params} label={"Countries"} variant="outlined" />
      )}
    />
  );
}

Edit Increase override specificity

Related answer:

Related documentation: