admin管理员组

文章数量:1355608

By default MaterialUI's Select ponent 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:

  • Through useRef(): this does nothing, no errors or anything, but does not blur my element

  • Through the document.activeElement: this gives me an error, apparently property blur does not exist on type element.

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

By default MaterialUI's Select ponent 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:

  • Through useRef(): this does nothing, no errors or anything, but does not blur my element

  • Through the document.activeElement: this gives me an error, apparently property blur does not exist on type element.

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

Share Improve this question asked Dec 22, 2020 at 16:03 theJulstheJuls 7,49019 gold badges96 silver badges182 bronze badges 6
  • You need to defer the blur effect. The focused element is not on the screen after selecting. – Akxe Commented Dec 29, 2020 at 21:22
  • 1 Looks like you are trying to blur the option, but I think you want to blur the select itself. Try selectElement.blur(); or evt.target.blur(); – 2pha Commented Dec 29, 2020 at 22:25
  • Note the ref is being forwarded to the root element (a wrapper div), not the select, which is why the that solution does nothing. – ericgio Commented Dec 29, 2020 at 23:20
  • The error you're seeing looks TypeScript-related, but you haven't included any typing in your question/code. – ericgio Commented Dec 29, 2020 at 23:42
  • I'm curious why you want to blur the Select. This seems like a horrible thing to do from an accessibility standpoint. – Ryan Cogswell Commented Dec 31, 2020 at 17:13
 |  Show 1 more ment

2 Answers 2

Reset to default 4

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

Summarizing some of the ments 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.

本文标签: