I am trying to set a maximum height in a MUI TextField with select property. I want to set the maximum height for the menu:
<TextField
fullWidth
label="Select State"
name="state"
onChange={handleChange}
required
select
SelectProps={{ native: true }}
value={values.state}
>
{states.map((option) => (
<option
key={option.value}
value={option.value}
>
{option.label}
</option>
))}
</TextField>
I tried to use MenuProps
, which works for the Select
component, but not for a TextField
:
<TextField
...
SelectProps={{
MenuProps: {
sx: { maxHeight: 200 }
}
}}
...
</TextField>
I also tried setting sx
and style
properties in TextField
.
How can I style this?
MUI creates the TextField
component using an interesting mix of native HTML elements, pseudo-elements, states and events. A simple size
attribute that behaves like the native HTML Select input field does not exist for TextField
. Due to mix of elements used, the TextField
SelectProps={{native:true}}
prop cannot be used if you want to limit the height of the menu options. MUI's MenuItem
s are needed to control the menu height. Perhaps the best solution is to use Theme style overrides which is demonstrated below.
The style override looks like this:
const theme = createTheme( {
components: {
MuiPopover: {
styleOverrides: {
root: {
'&#menu-TEXTFIELD_IDENTIFIER .MuiPaper-root.MuiMenu-paper.MuiPaper-elevation.MuiPaper-rounded.MuiPopover-paper': {
maxHeight: '86px' // Example maximum of two options displayed. About 43px per select option.
}
}
}
}
}
} );
The component used to display select menu options is a MuiPopover. A style override is used because this component cannot be easily selected using CSS selector rules with the sx property. MuiPopover is neither a sibling nor a descendant of the root element used for TextField
.
In the style override above, TEXTFIELD_IDENTIFIER is the id you assign to the id
property of the TextField
component. TextField
assigns the prefix menu- to the id
when generating the MuiPopover. Using this id
as part of the style override selector prevents the override from affecting every MuiPopover in your application.
Sample code is below. A live demo for the code is available.
In the demo, two select fields are displayed, but only the first is affected by the style override. Although ThemeProvider
is used here, it would typically be applied at the application entry point.
import * as React from 'react';
import {
Box,
TextField,
MenuItem
} from '@mui/material';
import { createTheme, ThemeProvider } from '@mui/material/styles';
interface selectOption {
value: string
}
const theme = createTheme( {
components: {
MuiPopover: {
styleOverrides: {
root: {
'&#menu-first-select-box .MuiPaper-root.MuiMenu-paper.MuiPaper-elevation.MuiPaper-rounded.MuiPopover-paper': {
maxHeight: '86px' // About 43px per select option.
}
}
}
}
}
} );
export default function ColorTextFields() {
const [ firstValue, setFirstValue ] = React.useState( 'One' );
const [ secondValue, setSecondValue ] = React.useState( 'Six' );
const firstOptions: selectOption[] = [
{ value: 'One' },
{ value: 'Two' },
{ value: 'Three' },
{ value: 'Four' },
{ value: 'Five' }
];
const secondOptions: selectOption[] = [
{ value: 'Six' },
{ value: 'Seven' },
{ value: 'Eight' },
{ value: 'Nine' },
{ value: 'Ten' }
];
function handleFirstChange( e: React.ChangeEvent<HTMLInputElement> ) {
setFirstValue( e.target.value );
}
function handleSecondChange( e: React.ChangeEvent<HTMLInputElement> ) {
setSecondValue( e.target.value );
}
function buildOptions( option: selectOption ): React.ReactElement<typeof MenuItem> {
return (
<MenuItem
key={ option.value }
id={ option.value }
value={ option.value }
>
{ option.value }
</MenuItem>
)
}
return (
<ThemeProvider theme={ theme }>
<Box
component="form"
sx={{
'& > :not(style)': { m: 1, width: '25ch' }
}}
noValidate
autoComplete="off"
>
<TextField
id={ 'first-select-box' }
name={ 'first-select-box' }
label="First Select"
select
SelectProps={ { native: false } }
variant="standard"
value={ firstValue }
onChange={ handleFirstChange }
>
{ firstOptions.map( buildOptions ) }
</TextField>
<TextField
id={ 'second-select-box' }
name={ 'second-select-box' }
label="Second select"
select
SelectProps={ { native: false } }
variant="outlined"
value={ secondValue }
onChange={ handleSecondChange }
>
{ secondOptions.map( buildOptions ) }
</TextField>
</Box>
</ThemeProvider>
);
}