-1

I'm looking for the Autocomplete element of Material UI and React for SolidJS. Many of the elements are available in Solid through https://suid.io/, but https://mui.com/material-ui/react-autocomplete/ seems to be missing. Is there any library available for this purpose? The goal is having a nicely styled SUID TextField that can be edited by the user, and it should be possible to select predefined options from a dropdown list.

It's also possible to specify the "select" attribute for the TextField, or specify an "input" element for Select. Is it possible to combine the two elements into one TextField that also has the dropdown list? What is the purpose of input for Select and select for TextField? I played with the attributes and only managed to get a normal TextField without the Select functionality. Any example or clarification would be welcome.

Ken White
  • 123,280
  • 14
  • 225
  • 444
vjalle
  • 549
  • 4
  • 13

1 Answers1

1

Not Material UI but there are some select libraries:

But you can create your own if you like:

  1. Create an options list below a text input field.
  2. Tie dropdown's visibility to input field's focus and blur events.
  3. Filter and show items on the list that partially matches with the input text.
  4. Create selected signal and use it to control selected element on dropdown list.
  5. Tie UpArrow and DownArrow keydown events to increment and decrement selected value.
  6. Tie Enter keydown to accept selected item and use it as input value.
  7. 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

snnsnn
  • 10,486
  • 4
  • 39
  • 44
  • Emphasis is on nicely styled, following the MUI look and feel. There are other libs that are not consistent with the MUI style, and your code is not, either. The problem is that the usage of the above fields is not well explained, and the demo code on their site does not work (everything else I tried worked fine, except connecting a Select and a TextField). Something is broken, and I can't figure whether it's Solid, SUID or MUI. What's happening is that the events seem to be not passed from the TextField to the Select. – vjalle Mar 16 '23 at 07:51
  • 1
    @vjalle Replace the elements like input and ul with MUI elements. You will get the look and feel. – snnsnn Mar 16 '23 at 08:13
  • Hmm, seems to be doable. The TextField works fine, but did not find a good solution for the menu yet. With the current code when the menu is displayed, the height of the object grows and the layout is disrupted. I guess that can be fixed too. My idea was using some standard styled component and not creating everything from scratch. But definitely a good exercide, learned a lot from this code! Thanks. – vjalle Mar 16 '23 at 10:17