theJuls
theJuls

Reputation: 7470

Blur Material UI Select component on the onChange event

By default MaterialUI's Select component leaves itself focused after selecting an option. This behaviour can be seen in all their examples in their docs

I would like the element to blur once something is selected. Here is what my code currently looks like:

const App = () => {
    const [selectedValue, setSelectedValue] = useState('')

    const selectElement = useRef(null);

  return (
        <Select
            native
            ref={selectElement}
            value={selectedValue}
            onChange={(evt) => {
                setSelectedValue(evt.target.value)

                // Attempt at blurring the element upon selection using the useRef:
                selectElement.current.blur(); // Nothing happens

                // Attempt at blurring the element upon selection using activeElement:
                document.activeElement.blur(); // Get Error: "Property 'blur' does not exist on type 'Element'."
            }}
        >
            <option value='option 1'>Option 1</option>
            <option value='option 2'>Option 2</option>
            <option value='option 3'>Option 3</option>
        </Select>
  );
};

As you can see in the code, I've tried to do this with two different methods I've found:

What is the proper method of blurring my Select component upon selecting an option?

Upvotes: 4

Views: 8535

Answers (2)

Rajiv
Rajiv

Reputation: 3772

inspired by @ericgio and @Ryan Cogswell answers there's another way to tackle this. For non-native elements, we can assign a setTimeout function to the onClose which will blur the element after selecting the option from menu.

const App = () => {
  const [selectedValue, setSelectedValue] = useState('');
  const [age, setAge] = React.useState('');

  const handleChange = (event) => {
    setAge(event.target.value);
  };

  return (
    <div>
      <div>
        <Select
          style={{ width: '200px' }}
          native
          value={selectedValue}
          onChange={(evt) => {
            setSelectedValue(evt.target.value);
            evt.target.blur();
          }}>
          <option value="option 1">Option 1</option>
          <option value="option 2">Option 2</option>
          <option value="option 3">Option 3</option>
        </Select>
      </div>
      <FormControl style={{ width: '200px' }}>
        <InputLabel id="demo-simple-select-label">Age</InputLabel>
        <Select
          onClose={() => {
            setTimeout(() => {
              document.activeElement.blur();
            }, 0);
          }}
          value={age}
          onChange={handleChange}>
          <MenuItem value={10}>Ten</MenuItem>
          <MenuItem value={20}>Twenty</MenuItem>
          <MenuItem value={30}>Thirty</MenuItem>
        </Select>
      </FormControl>
    </div>
  );
};

Sandbox:- https://codesandbox.io/s/wonderful-microservice-xufqc

Upvotes: 4

ericgio
ericgio

Reputation: 3519

Summarizing some of the comments into an answer:

As @2pha suggests, using evt.target.blur() is probably the way to go:

const App = () => {
  const [selectedValue, setSelectedValue] = useState('');

  return (
    <Select
      native
      value={selectedValue}
      onChange={(evt) => {
        setSelectedValue(evt.target.value);

        console.log(document.activeElement); // <select>
        evt.target.blur();
        console.log(document.activeElement); // <body>
      }}>
      <option value="option 1">Option 1</option>
      <option value="option 2">Option 2</option>
      <option value="option 3">Option 3</option>
    </Select>
  );
};

Sandbox: https://codesandbox.io/s/empty-night-oqlgr

The ref isn't working because it's being forwarded to the root element (a div) not the select element.

The error you're seeing related to document.activeElement looks TypeScript-related. You're seeing it because document.activeElement is generically typed as Element, which doesn't have a blur method. You'd need to specify the HTMLSelectElement type, but it doesn't seem worth pursuing that route since it's more straightforward to just use evt.target.

Upvotes: 3

Related Questions