I'm using material UI Select component and I'm trying to build a filter inside to display only the items that match the input entered by the user.
I build a minimal example of what I'm developing.
function App() {
const [selectedOption, setSelectedOption] = React.useState("");
const [filterExpression, setFilterExpression] = React.useState("");
const onChangeSelection = (
event: React.ChangeEvent<{ name?: string | undefined; value: unknown }>,
child: React.ReactNode
) => {
const value = event.target.value.toString();
setSelectedOption(value);
};
const onChangeExpression = (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const value = event.target.value.toString();
console.log(`value:`, value);
setFilterExpression(value);
};
const stopImmediatePropagation = (e: any) => {
e.stopPropagation();
e.preventDefault();
};
return (
<div className="App">
<Select onChange={onChangeSelection} value={selectedOption}>
<MenuItem
dense
divider
value={""}
onClickCapture={stopImmediatePropagation}
>
<TextField value={filterExpression} onChange={onChangeExpression} />
</MenuItem>
<MenuItem dense key={"One"} value={"One"}>
One
</MenuItem>
<MenuItem dense key={"Two"} value={"Two"}>
Two
</MenuItem>
<MenuItem dense key={"Three"} value={"Three"}>
Three
</MenuItem>
</Select>
</div>
);
}
My problem now is that by default the select component allows the user to press any letter and if there is an option in which the first letter matches the user input, it selects that option.
So, if I have 3 options (One
, Two
and Three
) and the user types O
the select component will select the One
option and the value of my text field won't change. However, if the user types F
the text field will be updated to F
.
I would like to disable this behavior, so, I have been trying to stop the propagation of events like onKeyUpCapture
, onChangeCapture
, onKeyDownCapture
but I haven't' been able to avoid this.
Do you have any suggestions to fix it? You can check the functional example here:
The text focus navigation functionality is implemented in the onKeyDown
of MenuList
(I implemented it about 6 months ago). Stopping propagation of that event on the MenuItem
(it would also work to stop propagation on the TextField
) prevents the event from reaching MenuList
.
import * as React from "react";
import { render } from "react-dom";
import TextField from "@material-ui/core/TextField";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
import "./styles.css";
function App() {
const [selectedOption, setSelectedOption] = React.useState("");
const [filterExpression, setFilterExpression] = React.useState("");
const onChangeSelection = (
event: React.ChangeEvent<{ name?: string | undefined; value: unknown }>,
child: React.ReactNode
) => {
const value = event.target.value.toString();
setSelectedOption(value);
};
const onChangeExpression = (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const value = event.target.value.toString();
console.log(`value:`, value);
setFilterExpression(value);
};
const stopImmediatePropagation = (e: any) => {
e.stopPropagation();
e.preventDefault();
};
return (
<div className="App">
<Select onChange={onChangeSelection} value={selectedOption}>
<MenuItem
dense
divider
value={""}
onClickCapture={stopImmediatePropagation}
onKeyDown={e => e.stopPropagation()}
>
<TextField value={filterExpression} onChange={onChangeExpression} />
</MenuItem>
<MenuItem dense key={"One"} value={"One"}>
One
</MenuItem>
<MenuItem dense key={"Two"} value={"Two"}>
Two
</MenuItem>
<MenuItem dense key={"Three"} value={"Three"}>
Three
</MenuItem>
</Select>
</div>
);
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With