Reputation: 7470
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:
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 component upon selecting an option?
Upvotes: 4
Views: 8535
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
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