Not Material UI but there are some select libraries:
But you can create your own if you like:
- Create an options list below a text input field.
- Tie dropdown's visibility to input field's focus and blur events.
- Filter and show items on the list that partially matches with the input text.
- Create
selected
signal and use it to control selected element on dropdown list.
- Tie
UpArrow
and DownArrow
keydown events to increment and decrement selected value.
- Tie
Enter
keydown to accept selected item and use it as input value.
- Hide options after accepting selected element.
Here is a working demo, you can improve on it. You can implement the mouse events on the list element for efficiency: Update the selected item on mousemove and update the text value on mousedown.
import { render } from 'solid-js/web';
import { Accessor, batch, Component, createEffect, createMemo, createSignal, For, JSX, on, Setter, Show } from 'solid-js';
const Select: Component<{
text: Accessor<string>,
setText: Setter<string>,
options: Array<string>
}> = (props) => {
const [show, setShow] = createSignal(false);
const [selected, setSelected] = createSignal(0);
const filteredOptions = () => props.options.filter(el => el.includes(props.text()));
const isVisible = createMemo(() => {
return show() && (filteredOptions().length > 1 || filteredOptions()[0] !== props.text());
});
createEffect(on(props.text, () => {
setSelected(0);
}));
const handleInput: JSX.EventHandlerUnion<HTMLInputElement, InputEvent> = (event) => {
props.setText(event.currentTarget.value);
};
const handleKeydown: JSX.EventHandler<HTMLInputElement, KeyboardEvent> = (event) => {
if (event.code === 'ArrowUp') {
setSelected(prev => prev === 0 ? (filteredOptions().length - 1) : prev - 1);
} else if (event.code === 'ArrowDown') {
setSelected(prev => prev + 1 === filteredOptions().length ? 0 : prev + 1);
} else if (event.code === 'Enter') {
props.setText(filteredOptions()[selected()]);
};
}
return (
<div>
<input
type="text"
value={props.text()}
onInput={handleInput}
onKeyDown={handleKeydown}
onFocus={() => setShow(true)}
onBlur={() => setShow(false)}
/>
<Show when={isVisible()}>
<ul style={`display: block; width: 100%; list-style: none; margin: 0; padding: 0`}>
<For each={filteredOptions()}>
{(item, i) => <li style={{ color: selected() === i() ? 'red': 'inherit'}}>{item}</li>}
</For>
</ul>
</Show>
</div>
);
};
export const App = () => {
const [text, setText] = createSignal("");
const options = ['Apple', 'Orange', 'Banana', 'Mango', 'Pear'];
return (
<div>
<Select text={text} setText={setText} options={options} />
</div>
);
};
render(() => <App />, document.body);
https://playground.solidjs.com/anonymous/e58974e7-287f-4f56-8ab3-33787d93c629