How to Add a Clear Button to the MUI Select Component

The Material-UI Select component is a great user input component with a list of options. However, it is a bad experience to require a user to click into the component and press “backspace” to clear it. In this tutorial I will show how to add a clear button inside the Select.

The biggest challenge is removing the arrow icon and replacing it with a clear icon. I only want the clear icon when the Select has a value, and I still want the arrow icon when no value is selected:

The arrow icon is rendered by default in the Material-UI Select and there are no props to disable it, so I had to get clever with styling.

Take a look at these useful links for more MUI Select resources:

Full code is in the Resources section.

How to Clear the MUI Select

The easiest way to clear the MUI Select component is to use a state value and then set this value as the value prop in the Select component:

<const [score, setScore] = useState('');

//JSX
<Select value={score} />

The score state value can be set to an empty string by a button inside the Select or by an external button. Here’s what the click handler looks like for either an internal or external button:

const handleClearClick = () => {
  setScore('');
};

How to Add a Clear Button to the MUI Select

The Select component appears to me to render the same as a TextField (in fact, the TextField has a select prop that converts it to a Select component).

MUI Select DOM with Clear Icon
MUI Select DOM with Clear Icon

However, the props for adding a clear button are a little bit different. Instead of setting InputProps.endAdornment, we can directly set the endAdornment prop:

endAdornment={<IconButton sx={{display: score? "": "none"}} onClick={handleClearClick}><ClearIcon/></IconButton>}

Notice how I make it display or not display based on the score state prop. This allows the clear button to be visible only when there is a value to clear.

Remember, a display: none component is not rendered. It is best to not render a component when possible to keep the DOM light. I did not see any jumping or strange render effects with display: none.

I also made the IconButton primary.blue on focus with the below nested selector, just like the Select outline does by default:

//Select level sx:
"&.Mui-focused .MuiIconButton-root": {color: 'primary.main'}

How to Remove the MUI Select Dropdown Arrow

I decided that I wanted the dropdown arrow to be visible only if no option is chosen.

//Select level sx:
"& .MuiSelect-iconOutlined": {display: score? 'none': ''}

This nested selector finds the .MuiSelect-iconOutlined class in the DOM, which wraps the dropdown arrow by default.

Using a state value for the Select allows us to manage all these styles that depend on whether the Select has been populated.

Resources

MUI Select Component Docs

import React, { useState } from 'react';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select, { SelectChangeEvent } from '@mui/material/Select';
import ClearIcon from "@mui/icons-material/Clear";
import IconButton from "@mui/material/IconButton";

export default function ClearSelect() {
  const [score, setScore] = useState('');
  const handleClearClick = () => {
    setScore('');
  };

  const scoreData = ["100", "90", "80", "70", "60", "50", "40", "30"];

  const handleChange = (event: SelectChangeEvent<string>) => {
    setScore(event.target.value);
  };

  return (
      <FormControl sx={{width: 200}}>
        {score.length ? <InputLabel id="custom-select-label">Score</InputLabel>: ''}
        <Select
          labelId="clearable-select-label"
          label={score.length ? "Score": ""}
          id="clearable-select"
          value={score}
          onChange={handleChange}
          displayEmpty
          sx={{"& .MuiSelect-iconOutlined": {display: score? 'none': ''}, "&.Mui-focused .MuiIconButton-root": {color: 'primary.main'}}}
          renderValue={(value) => value ? value : <em>Nothing Selected</em>}
          endAdornment={<IconButton sx={{visibility: score? "visible": "hidden"}} onClick={handleClearClick}><ClearIcon/></IconButton>}
        >
          {scoreData.map((scoreValue) => {
            return <MenuItem value={scoreValue}>{scoreValue}</MenuItem>
          })}
        </Select>
      </FormControl>
  );
}
Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.