Autocomplete

Import
import { Autocomplete } from "reshaped";
import type { AutocompleteProps, AutocompleteInstance } from "reshaped";
Related components

Autocomplete renders a TextField and a list of suggested values using the Autocomplete.Item compound components. The list is shown when the user focuses on the field and is hidden once they select a value or there are no items to render.

Autocomplete supports all TextField properties as well as additional onInput, onBackspace and onItemSelect handlers. Since Autocomplete is a form element, name is a required property for it to work. Here is a basic example that always renders the same passed items and autocompletes the field on selecting one of them:

function Component() {
  const [value, setValue] = React.useState("");
  const options = ["Pizza", "Pie", "Ice-cream"];

  const handleChange: AutocompleteProps["onChange"] = (args) =>
    setValue(args.value);

  return (
    <Autocomplete
      name="fruit"
      placeholder="Pick your food"
      value={value}
      onChange={handleChange}
    >
      {options.map((option) => (
        <Autocomplete.Item key={option} value={option}>
          {option}
        </Autocomplete.Item>
      ))}
    </Autocomplete>
  );

Autocomplete gives you full control over item rendering and filtering. You can remove any items based on user input or control asynchronous data loading.

function Component() {
  const [value, setValue] = React.useState("");
  const options = ["Pizza", "Pie", "Ice-cream"];

  const handleChange: AutocompleteProps["onChange"] = (args) =>
    setValue(args.value);

  return (
    <Autocomplete
      name="fruit"
      placeholder="Pick your food"
      value={value}
      onChange={handleChange}
    >
      {options.map((option) => {
        if (!option.toLowerCase().includes(value.toLowerCase())) return;

        return (
          <Autocomplete.Item key={option} value={option}>
            {option}
          </Autocomplete.Item>
        );
      })}
    </Autocomplete>
  );

You can fully customize the composition of the dropdown content. Autocomplete.Item supports the same properties as MenuItem, making each item's layout very flexible and allowing custom wrappers around the items. Use onItemSelect when you want to render something in the field only when an item is selected, not on every value change.

const options = [
  {
    title: "Paul Farell",
    role: "Designer",
    photo: "/img/examples/avatar-3.png",
  },
  {
    title: "Esther Naomi",
    role: "Developer",
    photo: "/img/examples/avatar-2.png",
  },
  {
    title: "Whitney Raynolds",
    role: "Developer",
    photo: "/img/examples/avatar-1.png",
  },
];

function Component() {
  const [value, setValue] = React.useState("");
  const [selectedItem, setSelectedItem] = React.useState("");

  const handleChange: AutocompleteProps["onChange"] = (args) =>
    setValue(args.value);

  const handleItemSelect: AutocompleteProps["onItemSelect"] = (args) => {
    setSelectedItem(args.value);
    setValue("");
  };

  return (
    <Autocomplete
      name="people"
      placeholder="Pick assignee"
      value={value}
      onChange={handleChange}
      onItemSelect={handleItemSelect}
      startSlot={selectedItem && <Badge>{selectedItem}</Badge>}
    >
      {options.map((option) => {
        const valueMatch = value.toLowerCase();
        const optionValue = option.title.toLowerCase();

        if (!optionValue.includes(valueMatch) || valueMatch === optionValue)
          return;

        return (
          <Autocomplete.Item
            key={option.title}
            value={option.title}
            startSlot={<Avatar src={option.photo} size={7} />}
            endSlot={<Badge>{option.role}</Badge>}
          >
            {option.title}
          </Autocomplete.Item>
        );
      })}
    </Autocomplete>
  );

If you're using the start slot to display selected values, apply the multiline flag to make the selected values wrap onto the next line.

Cinnamon bun
Pasta
Ice-cream
Pizza
function Component() {
  const options = ["Salad", "Quinoa", "Beans"];

  return (
    <View width="280px">
      <Autocomplete
        name="food"
        placeholder="Pick your favorite food"
        startSlot={[
          <Badge size="small">Cinnamon bun</Badge>,
          <Badge size="small">Pasta</Badge>,
          <Badge size="small">Ice-cream</Badge>,
          <Badge size="small">Pizza</Badge>,
        ]}
        defaultValue="Pineapple"
        multiline
      >
        {options.map((option) => {
          return (
            <Autocomplete.Item key={option} value={option}>
              {option}
            </Autocomplete.Item>
          );
        })}
      </Autocomplete>
    </View>
  );

When working with custom data structures, you can pass any data value to the Autocomplete.Item and later use it inside the onItemSelect:

const options = [
  { name: "Pizza", id: 1 },
  { name: "Pie", id: 2 },
  { name: "Ice-cream", id: 3 },
];

const [selectedItem, setSelectedItem] = useState(null);

const handleItemSelect = (args) => setSelectedItem(args.data);

return (
  <Autocomplete name="food" placeholder="Pick your food" value={value}>
    {options.map((option) => (
      <Autocomplete.Item key={option.id} value={option.name} data={option}>
        {option.name}
      </Autocomplete.Item>
    ))}
  </Autocomplete>
);

To let the user know what data you expect them to type in, add labels or status messages to your fields with the help of the FormControl utility. In case you're using xlarge TextField size, you can also combine it with the large FormControl size for better visual alignment. Don't use placeholders as labels for the fields as users won't see the placeholder when input contains a value.

function Component() {
  const [value, setValue] = React.useState("");
  const options = ["Pizza", "Pie", "Ice-cream"];

  const handleChange: AutocompleteProps["onChange"] = (args) =>
    setValue(args.value);

  return (
    <FormControl>
      <FormControl.Label>Favorite food</FormControl.Label>
      <Autocomplete
        name="fruit"
        placeholder="Pick your option"
        value={value}
        onChange={handleChange}
      >
        {options.map((option) => (
          <Autocomplete.Item key={option} value={option}>
            {option}
          </Autocomplete.Item>
        ))}
      </Autocomplete>
    </FormControl>
  );

Autocomplete supports responsive syntax for the size property. Use object syntax to control its value based on the viewport size. Responsive properties are mobile-first, so selecting a value for a viewport will also apply it to all wider viewports.

<Autocomplete size={{ s: "medium", l: "large" }} />
  • ArrowDown - open the dropdown while the text field is focused and at least one value is available
  • Esc - close the dropdown
  • ArrowUp / ArrowDown - navigate the autocomplete items
  • Enter - select the focused autocomplete item
  • Tab - close the dropdown and move the focus to the next element after the text field
  • Shift + Tab - close the dropdown and keep the focus on the text field
  • When using Autocomplete without a label, provide a text description by passing inputAttributes={{ 'aria-label': 'Your label' }} to the component.
Previous
Next