Search code examples
reactjsmaterial-uithemes

overriding size (height) on a Material UI TextField


I'm using React (v5) and Material UI with TypeScript.

I'd like to be able to support TextFields in large as well as small and medium. There are specific heights to be associated with those sizes.

I augmented the TextField module to register the new value for the size attribute:

declare module '@mui/material/TextField' {
  interface TextFieldPropsSizeOverrides {
    large: true;
  }
}

I'd like the default to be medium.
I want the heights to apply to <TextField select> as well as "regular" <TextField> elements, so I believe I want to override the height on the MuiInputBase child element.

Here's what I'm passing to createTheme():

  components: {
    MuiTextField: {
      styleOverrides: {
        root: {
          '& .MuiInputBase-root': {
            height: '48px',
          },
          '&[size="medium"] .MuiInputBase-root': {
            height: '48px',
          },
          '&[size="small"] .MuiInputBase-root': {
            height: '32px',
          },
          '&[size="large"] .MuiInputBase-root': {
            height: '56px',
          },
          ...

The base style does get applied -- text fields are 48px high.
And I can specify size="large" on my TextFields without getting build / syntax check errors.
But doing so has no effect: the fields remain at the base height (48px).

I also tried using a marker CSS class, i.e.

          '&.myapp-lg .MuiInputBase-root': {
            height: '56px',
          },

... and adding className="myapp-lg" to the TextField. But, again, the style rule is ignored.

I understand I could use a styled component, but that seems like a lot of overhead just to control the sizing.

I also understand I could potentially define a custom variant for the TextField. But that's not really what variants are for (at least as I understand it); and what I really want to do is "inherit" the styling -- except the size -- of existing variants.

Am I getting the incantation(s) wrong? (I feel like I must be missing something obvious.)
...or is this perhaps a limitation of the theming subsystem?


Solution

  • I managed to get the marker class approach working.

    The "flattened" style rule doesn't work for whatever reason. But if you nest the rule for the inner div, it does work:

    components: {
      MuiTextField: {
        styleOverrides: {
          root: {
            ...
            '&.myapp-lg': {
              height: '56px',
              '& .MuiInputBase-root': {
                height: '56px',
              },
            },
            ...
    

    ... this answer to a related question is what put me on the right track.
    I have seen similar behavior in the past when using LESS, I probably should have tried something like this sooner.
    But again, the marker class approach is more of a workaround then a solution IMHO.


    Checking for an attribute e.g. [size="large"] doesn't work because that's not how React generates the final markup. (Duh.)
    Instead, when React generates the nested <div> with CSS class MuiInputBase, an additional marker class is applied to that nested div, in this case, MuiInputBase-sizeLarge.
    So the object passed to createTheme needs to be:

      components: {
        MuiTextField: {
          styleOverrides: {
            root: {
              ...
              //&[size="large"]
              '& .MuiInputBase-sizeLarge': {
                height: '56px',
              },
              ...