Mui autocomplete error

Автодополнение - это обычный ввод текста, дополненный панелью предлагаемых опций.

Автодополнение — это обычный ввод текста, дополненный панелью предлагаемых опций.

Этот виджет используется для установки значения однострочного текстового поля. Он полезен в одном из двух случев:

  1. Значение для текстового поля должно быть выбрано из предопределенного набора допустимых значений, например, поле местоположения должно содержать действительное имя местоположения: поле со списком.
  2. Текстовое поле может содержать любое произвольное значение, но целесообразно предлагать пользователю возможные значения. Например, поле поиска может предлагать аналогичные или предыдущие поиски, чтобы сэкономить время пользователя: free solo.

It’s meant to be an improved version of the «react-select» and «downshift» packages.

  • Обратная связь
  • WAI-ARIA
  • Размер пакета
  • Figma
  • Adobe
  • Sketch

Комбо-Бокс

Значение должно быть выбрано из предопределенного набора допустимых значений.

<Autocomplete
  disablePortal
  id="combo-box-demo"
  options={top100Films}
  sx={{ width: 300 }}
  renderInput={(params) => <TextField {...params} label="Movie" />}
/>

Песочница

By default, the component accepts the following options structures:

const filterOptions = createFilterOptions({
  matchFrom: 'start',
  stringify: option => option.title,
});

<Autocomplete filterOptions={filterOptions} />

например:

const options = [
  { label: 'The Godfather', id: 1 },
  { label: 'Pulp Fiction', id: 2 },
];
// or
const options = ['The Godfather', 'Pulp Fiction'];

However, you can use different structures by providing a getOptionLabel prop.

Песочница

Каждый из следующих примеров демонстрирует одну функцию компонента автозаполнения.

Выбор страны

Choose one of the 248 countries.

Controllable states

The component has two states that can be controlled:

  1. the «value» state with the value/onChange props combination. This state represents the value selected by the user, for instance when pressing Enter.
  2. the «input value» state with the inputValue/onInputChange props combination. This state represents the value displayed in the textbox.

⚠️ These two state are isolated, they should be controlled independently.

value: ‘Option 1’

inputValue: »

Произвольное значение

Установите для freeSolo значение true, чтобы текстовое поле могло содержать любое произвольное значение.

Ввод для поиска

Вы также можете показать диалоговое окно, если пользователь хочет добавить новое значение.

Создаваемый

If you intend to use this mode for a combo box like experience (an enhanced version of a select element) we recommend setting:

  • selectOnFocus to helps the user clear the selected value.
  • clearOnBlur to helps the user to enter a new value.
  • handleHomeEndKeys to move focus inside the popup with the Home and End keys.
  • A last option, for instance Add "YOUR SEARCH".

Вы также можете показать диалоговое окно, если пользователь хочет добавить новое значение.

Сгруппированные

You can group the options with the groupBy prop. If you do so, make sure that the options are also sorted with the same dimension that they are grouped by, otherwise you will notice duplicate headers.

<Autocomplete
  id="grouped-demo"
  options={options.sort((a, b) => -b.firstLetter.localeCompare(a.firstLetter))}
  groupBy={(option) => option.firstLetter}
  getOptionLabel={(option) => option.title}
  sx={{ width: 300 }}
  renderInput={(params) => <TextField {...params} label="With categories" />}
/>

Отключенные опции

<Autocomplete
  id="disabled-options-demo"
  options={timeSlots}
  getOptionDisabled={(option) =>
    option === timeSlots[0] || option === timeSlots[2]
  }
  sx={{ width: 300 }}
  renderInput={(params) => <TextField {...params} label="Disabled options" />}
/>

useAutocomplete

For advanced customization use cases, we expose a headless useAutocomplete() hook. It accepts almost the same options as the Autocomplete component minus all the props related to the rendering of JSX. The Autocomplete component uses this hook internally.

import useAutocomplete from '@material-ui/core/useAutocomplete';
  • 4.5 4,5 кБ в сжатом виде.

Customized hook

Head to the Customized Autocomplete section for a customization example with the Autocomplete component instead of the hook.

Асинхронные запросы

The component supports two different asynchronous use-cases:

  • Load on open: it waits for the component to be interacted with to load the options.
  • Search as you type: a new request is made for each keystroke.

Load on open

It displays a progress state as long as the network request is pending.

Search as you type

If your logic is fetching new options on each keystroke and using the current value of the textbox to filter on the server, you may want to consider throttling requests.

Additionally, you will need to disable the built-in filtering of the Autocomplete component by overriding the filterOptions prop:

import matchSorter from 'match-sorter';

const filterOptions = (options, { inputValue }) =>
  matchSorter(options, inputValue);

<Autocomplete filterOptions={filterOptions} />

Места Google Maps

A customized UI for Google Maps Places Autocomplete.

For this demo, we need to load the Google Maps JavaScript API.

⚠️ Перед началом использования API карт Google, JavaScript необходимо зарегистрировать и создать учетную запись для выставления счетов.

Множественные значения

Also known as tags, the user is allowed to enter more than one value.

Фиксированные опции

В случае, если вам нужно зафиксировать определенный тег (так что он не мог быть удалён через интерфейс), вы можете установить chips в состояние disabled.

Чекбоксы

Limit tags

You can use the limitTags prop to limit the number of displayed options when not focused.

<Autocomplete
  multiple
  limitTags={2}
  id="multiple-limit-tags"
  options={top100Films}
  getOptionLabel={(option) => option.title}
  defaultValue={[top100Films[13], top100Films[12], top100Films[11]]}
  renderInput={(params) => (
    <TextField {...params} label="limitTags" placeholder="Favorites" />
  )}
/>

Размеры

Fancy smaller inputs? Use the size prop.

Кастомизация

Custom input

The renderInput prop allows you to customize the rendered input. The first argument of this render prop contains props that you need to forward. Pay specific attention to the ref and inputProps keys.

GitHub’s picker

This demo reproduces the GitHub’s label picker:

Head to the Customized hook section for a customization example with the useAutocomplete hook instead of the component.

Основные моменты

The following demo relies on autosuggest-highlight, a small (1 kB) utility for highlighting text in autosuggest and autocomplete components.

Пользовательский фильтр

The component exposes a factory to create a filter method that can provided to the filterOptions prop. You can use it to change the default option filter behavior.

import { createFilterOptions } from '@material-ui/core/Autocomplete';

createFilterOptions(config) => filterOptions

Аргументы

  1. config (Object [optional]):
  • config.ignoreAccents (Boolean [optional]): Defaults to true. Remove diacritics.
  • config.ignoreCase (Boolean [optional]): Defaults to true. Lowercase everything.
  • config.limit (Number [optional]): Default to null. Limit the number of suggested options to be shown. For example, if config.limit is 100, only the first 100 matching options are shown. It can be useful if a lot of options match and virtualization wasn’t set up.
  • config.matchFrom (‘any’ | ‘start’ [optional]): Defaults to 'any'.
  • config.stringify (Func [optional]): Controls how an option is converted into a string so that it can be matched against the input text fragment.
  • config.trim (Boolean [optional]): По умолчанию — false. Remove trailing spaces.

Возвращает

filterOptions: the returned filter method can be provided directly to the filterOptions prop of the Autocomplete component, or the parameter of the same name for the hook.

In the following demo, the options need to start with the query prefix:

const filterOptions = createFilterOptions({
  matchFrom: 'start',
  stringify: (option) => option.title,
});

<Autocomplete filterOptions={filterOptions} />;

Дополнительные параметры

For richer filtering mechanisms, like fuzzy matching, it’s recommended to look at match-sorter. Например:

import matchSorter from 'match-sorter';

const filterOptions = (options, { inputValue }) => matchSorter(options, inputValue);

<Autocomplete filterOptions={filterOptions} />;

Виртуализация

Поиск в 10000 случайно сгенерированных опций. Список виртуализирован благодаря реагирующему окну.

<Autocomplete
  id="virtualize-demo"
  sx={{ width: 300 }}
  disableListWrap
  PopperComponent={StyledPopper}
  ListboxComponent={ListboxComponent}
  renderGroup={renderGroup}
  options={OPTIONS}
  groupBy={(option) => option[0].toUpperCase()}
  renderInput={(params) => <TextField {...params} label="10,000 options" />}
  renderOption={(props, option) => (
    <li {...props}>
      <Typography noWrap>{option}</Typography>
    </li>
  )}
/>

Events

If you would like to prevent the default key handler behavior, you can set the event’s defaultMuiPrevented property to true:

<Autocomplete
  onKeyDown={(event) => {
    if (event.key === 'Enter') {
      // Prevent's default 'Enter' behavior.
      event.defaultMuiPrevented = false;
      // your handler code
    }
  }}
/>

Ограничения

Автозаполнение

The browsers have heuristics to help the users fill the form inputs. However, it can harm the UX of the component.

By default, the component disables the autocomplete feature (remembering what the user has typed for a given field in a previous session) with the autoComplete="off" attribute. Google Chrome does not currently support this attribute setting (Issue 587466). A possible workaround is to remove the id to have the component generate a random one.

In addition to remembering past entered values, the browser might also propose autofill suggestions (saved login, address, or payment details). In the event you want the avoid autofill, you can try the following:

  • Name the input without leaking any information the browser can use. e.g. id="field1" instead of id="country". If you leave the id empty, the component uses a random id.

  • Set autoComplete="new-password" (some browsers will suggest a strong password for inputs with this attribute setting):

    <TextField
      {...params}
      inputProps={{
        ...params.inputProps,
        autoComplete: 'new-password',
      }}
    />
    

Read the guide on MDN for more details.

iOS VoiceOver

VoiceOver on iOS Safari doesn’t support the aria-owns attribute very well. You can work around the issue with the disablePortal prop.

ListboxComponent

If you provide a custom ListboxComponent prop, you need to make sure that the intended scroll container has the role attribute set to listbox. This ensures the correct behavior of the scroll, for example when using the keyboard to navigate.

Доступность

(WAI-ARIA: https://www.w3.org/TR/wai-aria-practices/#combobox)

We encourage the usage of a label for the textbox. The component implements the WAI-ARIA authoring practices.

The Autocomplete component is useful for giving the user limited options to select from. When a choice is selected it populates an Input subcomponent. Autocomplete has a ‘clear’ button for removing the selected choice.

In this post we will:

  • Add a custom clear event handler
  • Style the clear button
  • Remove the clear button
MUI Autocomplete Clear
MUI Autocomplete Clear

The clear button is only visible on hover of the Input (by default).

Full code for this tutorial is in the Resources section.

Here’s a YouTube video version of this post or watch below:

In MUI, most events are available for custom handling through the component API. However, the Autocomplete API does not directly have a clear event or onClear prop (There is a solution, keep reading).

Here’s the TypeScript error I get when I try to add onClear:

MUI Autocomplete onClear (Does Not Exist)
MUI Autocomplete onClear (Does Not Exist)

The solution: when the clear button is clicked, the onChange handler is fired. We can use this handler for any custom handling of the clear event.

const handleChange = (event: React.SyntheticEvent<Element, Event>, value: trailData | null) => {
    console.log(value)
}

<Autocomplete onChange={handleChange} />

In the above code, I log the new value onChange. Notice my TypeScript typing of the value prop.

Style MUI Autocomplete Clear Button

I decided the “cancel” button in the TextField Input (it only shows on hover) should also be styled blue. In the same class I added the following:

tfStyle: {
  "& .MuiButtonBase-root.MuiAutocomplete-clearIndicator": {
    color: "blue",
    visibility: "visible"
  }
}

Notice how even the indicator has a specific class applied by Material-UI since it is inside the Autocomplete.

Also, you can swap the tooltip text that appears on hover with the clearText prop.

MUI Autocomplete Clear Icon

You can replace the clear icon with a custom icon by using the clearIcon prop.

Here’s example code:

<Autocomplete clearIcon={<HighlightOffIcon/>} />

Notice that the clearIcon prop requires a value of type node.

MUI Autocomplete Clear Icon
MUI Autocomplete Clear Icon

Remove MUI Autocomplete Clear Button

The ‘Clear’ Button can be removed by using the disableClearable prop:

<Autocomplete disableClearable />

With this prop enabled, the clear button is no longer rendered as part of the Autocomplete Input’s endAdornment element.

You might want to disable the clear button if you enable the clearOnEscape prop. This will clear a value that was selected while the Autocomplete is in a focus state. It will not clear a value that was previously selected.

Adding a clear button to the Select component is more challenging.

Resources

You can use MUI’s ClickAwayListener to create your own Autocomplete.

MUI Autocomplete API Docs

import Autocomplete from "@mui/material/Autocomplete";
import TextField from "@mui/material/TextField";
import HighlightOffIcon from "@mui/icons-material/HighlightOff";

interface trailData {
  name: string;
  state: string;
}

const tfStyle = {
  "& .MuiButtonBase-root.MuiAutocomplete-clearIndicator": {
    color: "blue",
    visibility: "visible",
  },
};

const handleChange = (
  event: React.SyntheticEvent<Element, Event>,
  value: trailData | null
) => {
  console.log(value);
};

export default function ClearAutocomplete() {
  return (
    <Autocomplete
      onChange={handleChange}
      options={myTrails}
      //disableClearable
      //clearOnEscape
      //clearIcon={<HighlightOffIcon/>}
      id="autocomplete-1"
      getOptionLabel={(option) => `${option.name}: ${option.state}`}
      renderInput={(params) => {
        return (
          <TextField
            {...params}
            variant="outlined"
            label="Name: State"
            sx={tfStyle}
          />
        );
      }}
      sx={{ mb: 2, minWidth: 400 }}
    />
  );
}

const myTrails = [
  {
    name: "Eagle Mountain Lake",
    state: "Texas",
  },
  {
    name: "Inks Lake Woodland Trail",
    state: "Texas",
  },
  {
    name: "Tanyard Creek Loop",
    state: "Arkansas",
  },
  {
    name: "Turner Falls Park",
    state: "Oklahoma",
  },
];

Table of Contents

  1. Introduction
  2. What is Material UI Autocomplete Component?
  3. Setting up a React App
  4. Installing Material UI Library
  5. How does Autocomplete work in Material UI?
  6. Rendering Material UI Autocomplete Component
  7. Rendering Material UI Autocomplete Component As Normal Text Input
  8. Material UI Autocomplete Free Solo Prop
  9. Getting Multiple Values from Material UI Autocomplete Component
  10. Getting the Selected Value from the Material UI Autocomplete Component
  11. Getting Multiple Selected values from the Material UI Autocomplete
  12. Setting Default Multiple Selected Values in the Material UI Autocomplete
  13. Rendering Array Of Objects in Material UI Autocomplete Component
  14. Wrapping Up
  15. Interesting Reads From Our Blogs

Do you want to be more efficient? Consider CopyCat, an AI-powered plugin that will convert your Figma design to UI code, allowing you to concentrate on the app’s business logic.

Introduction

According to Wikipedia: Autocomplete speeds up human-computer interactions when it correctly predicts the word a user intends to enter after only a few characters have been typed into a text input field.

In this article, we’ll look at how to use the Material UI autocomplete component. Speed up user interaction with your web application by incorporating an autocomplete component into your form select element, which leads to better search results.

What is Material UI Autocomplete Component?

Material UI Autocomplete component is a great way to implement an autocomplete feature in React and according to the MUI documentation. “It is a normal text input enhanced by a panel of suggested options.”

This component provides predictive search result that makes it possible for the user to know if there are related result for their keyword even before they complete the word or sentence they’re typing.

Below is a demo of the Material UI Autocomplete component in action:

Setting up a React App

Use the following command to create a new react application:

npx create-react-app my-app

Next, run the following command to navigate to your newly generated app directory:

Then run the following command to start your React server:

Or using npm:

Your server should launch in your browser at http://localhost:3000, as shown below:

Installing Material UI Library

In this section, we’ll install the Material UI library. Run the command below to install Material UI to your project:

npm:

npm install @mui/material @emotion/react @emotion/styled

yarn:

yarn add @mui/material @emotion/react @emotion/styled

How does Autocomplete work in Material UI?

Using the Autocomplete component is relatively simple. You’ll need to provide the Autocomplete component with a list of options and a callback function that will handle the selection when the input changes.

Rendering Material UI Autocomplete Component

Given that our task is to display an array of pets in a searchable dropdown list from which users can choose their favorite pet.

 const pets = ["Cat", "Dog", "Bird", "Pigeon"];

To start;

  • Create a new component folder inside the src folder.
  • Next, create a new PetsList.jsx file inside the component folder.

Copy and paste the code below inside the PetsList.jsx file:

import { Autocomplete, TextField } from "@mui/material";
import React from "react";

export const PetLists = () => {
  const pets = ["Cat", "Dog", "Bird", "Pigeon"];
  return (
    <Autocomplete
      style={{ width: "20%" }}
      options={pets}
      renderInput={(params) => (
        <TextField label='Select your favourite pet' {...params} />
      )}
    ></Autocomplete>
  );
};

ThePetLists component declares a constant variable called pets and sets it equal to an array of four pets names.

Next, we render the Autocomplete component with an optional style of 20% width of it’s parent element, a required options prop set to the pets array we created, this will be the dropdown options, and a renderInput prop that returns another MUI component called TextField with a label and params rest operator.

Finally, render the PetsList component in your App.js file as shown below:

import React from "react";
import { Grid } from "@mui/material";
import { PetLists } from "./components/PetLists";

function App() {
  return (
    <React.Fragment>
      <Grid
        container
        direction='column'
        alignItems='center'
        justifyContent='center'
        style={{ minHeight: "100vh" }}
      >
        <PetLists />
      </Grid>
    </React.Fragment>
  );
}

export default App;

We use the MUI Grid component to center the PetLists component horizontally and vertically. More information on the MUI grid component is here.

When you visit your browser, the PetLists component should look something like this:

Cool 😎, right!

Rendering Material UI Autocomplete Component As Normal Text Input

We can render customized components or elements such as the native HTML input tag in the renderInput prop instead of the MUI TextField component as shown below:

import { Autocomplete } from "@mui/material";
import React from "react";

export const PetLists = () => {
  const pets = ["Cat", "Dog", "Bird", "Pigeon"];

  return (
    <Autocomplete
      style={{ width: "20%" }}
      options={pets}
      renderInput={(params) => {
        return (
          <div ref={params.InputProps.ref}>
            <label for='pets-lists'>Select your favourite pet:</label>
            <input
              id='pets-lists'
              type='text'
              placeholder='Start typing...'
              style={{
                border: "1px solid #cccccc",
                padding: "10px",
                width: "100%",
              }}
              {...params.inputProps}
            />
          </div>
        );
      }}
    ></Autocomplete>
  );
};

It is important to pass the ref to the parent container of the custom component or element and also pass or spread the …params.inputProps to the element in order to be controlled by MUI.

The above Autocomplete component with the native input tag will look and function something like this:

Material UI Autocomplete Free Solo Prop

Pass the freesolo prop to the Autocomplete component if you wish to render the Material UI Autocomplete component to accept undetermined values, the freesolo prop is declared in the Autocomplete component as follows:

import { Autocomplete, TextField } from "@mui/material";
import React from "react";

export const PetLists = () => {
  const pets = ["Cat", "Dog", "Bird", "Pigeon"];
  return (
    <Autocomplete
      freesolo
      style={{ width: "20%" }}
      options={pets}
      renderInput={(params) => {
        return <TextField 
          label='Select your favourite pet'
          {...params} 
        />
      }}
    ></Autocomplete>
  );
};

The primary aim of this prop is to provide search suggestions for inputs like Google’s search engine that usually contains an arbitrary values, similar or previous searches from a predefined set of values.

Getting Multiple Values from Material UI Autocomplete Component

Pass the multiple prop to the Autocomplete component to enable multi-selection in the dropdown.

import { Autocomplete, TextField } from "@mui/material";
import React from "react";

export const PetLists = () => {
  const pets = ["Cat", "Dog", "Bird", "Pigeon"];

  return (
    <Autocomplete
      multiple
      style={{ width: "20%" }}
      options={pets}
      renderInput={(params) => {
        return <TextField label='Select your favourite pet' {...params} />;
      }}
    ></Autocomplete>
  );
};

This way, the user will be able to choose as many options as they want from the available sets of options. The MUI multi-select with autocomplete will look and function like below:

Getting the Selected Value from the Material UI Autocomplete Component

The autocomplete component provides us with some useful props to control the input value and the selected options in the Autocomplete component.

  • The value prop: To control the option selected by the user.
  • The onChange prop: To trigger an action when a new option is selected.
  • The inputValue prop: To control and access the keyword entered by the user.
  • The onInputChange prop: To trigger an action each time the user types a keyword in the search input.

We’ll make use of the useState hook to keep track of the selected option (value) from the autocomplete component, we’ll also console.log and render the selectedPet in the browser, so we can see the changes in real time.

import { Autocomplete, TextField } from "@mui/material";
import React, { useState } from "react";

export const PetLists = () => {
  const pets = ["Cat", "Dog", "Bird", "Pigeon"];
  const [selectedPet, setSelectedPet] = useState(null);
  const [petInputValue, setPetInputValue] = useState("");

  console.log(selectedPet);

  return (
    <React.Fragment>
      <h5 style={{ marginBottom: "1rem", textAlign: "left" }}>
        You selected:{" "}
        <span style={{ color: "dodgerblue", fontWeight: "800" }}>
          {selectedPet}
        </span>
      </h5>
      <Autocomplete
        style={{ width: "40%" }}
        options={pets}
        value={selectedPet}
        onChange={(event, newPet) => {
          setSelectedPet(newPet);
        }}
        inputValue={petInputValue}
        onInputChange={(event, newPetInputValue) => {
          setPetInputValue(newPetInputValue);
        }}
        renderInput={(params) => {
          return <TextField label='Select your favourite pet' {...params} />;
        }}
      ></Autocomplete>
    </React.Fragment>
  );
};

The above code will function as demonstrated below:

As demonstrated above, the option selected is captured and rendered in both dom and the browser console.

Getting Multiple Selected values from the Material UI Autocomplete

For the multiple selected values, the initial value for the useState will be an empty array and we’ll remove the value prop from the Autocomplete component, MUI will handle the value for us once we pass the multiple prop in the Autocomplete component.

We’ll also map the selectedPets to the UI to see the selected options in realtime.

import { Autocomplete, TextField } from "@mui/material";
import React, { useState } from "react";

export const PetLists = () => {
  const pets = ["Cat", "Dog", "Bird", "Pigeon"];
  const [selectedPets, setSelectedPets] = useState([]);
  const [petInputValue, setPetInputValue] = useState("");

  console.log(selectedPets);

  return (
    <React.Fragment>
      <h5 style={{ marginBottom: "1rem", textAlign: "left" }}>
        You selected:{" "}
        <span style={{ color: "dodgerblue", fontWeight: "800" }}>
          {selectedPets
            .map((pet, i, arr) =>
              arr.length > 1 && arr.length - 1 === i ? ` and ${pet}.` : pet
            )
            .join(", ") || "Nothing yet"}
        </span>
      </h5>
      <Autocomplete
        multiple
        style={{ width: "40%" }}
        options={pets}
        onChange={(event, newPet) => {
          setSelectedPets(newPet);
        }}
        inputValue={petInputValue}
        onInputChange={(event, newPetInputValue) => {
          setPetInputValue(newPetInputValue);
        }}
        renderInput={(params) => {
          return <TextField label='Select your favourite pets' {...params} />;
        }}
      ></Autocomplete>
    </React.Fragment>
  );
};

The above component will function as follows:

As demonstrated above, the selected options are added to the list within the input and are removable through the close icons.

Setting Default Multiple Selected Values in the Material UI Autocomplete

You can set a default value for the multiple select option in the useState and defaultValue prop in the Autocomplete component as follows:

import { Autocomplete, TextField } from "@mui/material";
import React, { useState } from "react";

export const PetLists = () => {
  const pets = ["Cat", "Dog", "Bird", "Pigeon"];
  const [selectedPets, setSelectedPets] = useState([pets[2], pets[3]]);
  const [petInputValue, setPetInputValue] = useState("");

  console.log(selectedPets);

  return (
    <React.Fragment>
      <h5 style={{ marginBottom: "1rem", textAlign: "left" }}>
        You selected:{" "}
        <span style={{ color: "dodgerblue", fontWeight: "800" }}>
          {selectedPets
            .map((pet, i, arr) =>
              arr.length > 1 && arr.length - 1 === i ? ` and ${pet}.` : pet
            )
            .join(", ") || "Nothing yet"}
        </span>
      </h5>
      <Autocomplete
        multiple
        defaultValue={selectedPets}
        style={{ width: "40%" }}
        options={pets}
        onChange={(event, newPet) => {
          setSelectedPets(newPet);
        }}
        inputValue={petInputValue}
        onInputChange={(event, newPetInputValue) => {
          setPetInputValue(newPetInputValue);
        }}
        renderInput={(params) => {
          return <TextField label='Select your favourite pets' {...params} />;
        }}
      ></Autocomplete>
    </React.Fragment>
  );
};

Note that the default value must be an array when using the multiple prop.

Our default multiple selected options rendered shown below:

Rendering Array Of Objects in Material UI Autocomplete Component

Given that you’re to render an array of pets objects with name and img properties as structured below:

const pets = [
  { name: "Cats", img: "🐈" },
  { name: "Dog", img: "🦮" },
  { name: "Bird", img: "🦜" },
];

We’ll make use of the autocomplete getOptionLabel prop to specify the key in the object that we want to render as the option.

Below will be our getOptionLabel given that we want to use the name key as our option:

getOptionLabel={(option) => option.name}

We can also customize the dropdown option label through the renderOption prop as shown below:

renderOption={(props, option) => (
  <Box component='li' {...props}>
    {option.name} {option.img}
  </Box>
)}

This will render the name and image of the pet objects side by side in the dropdown options like this Cat 🐈.

Putting everything together, our component will look like this:

import { Autocomplete, TextField } from "@mui/material";
import { Box } from "@mui/system";
import React, { useState } from "react";

export const PetLists = () => {
  const pets = [
    { name: "Cats", img: "🐈" },
    { name: "Dog", img: "🦮" },
    { name: "Bird", img: "🦜" },
  ];
  const [selectedPet, setSelectedPet] = useState(null);
  const [petInputValue, setPetInputValue] = useState("");

  console.log(selectedPet);

  return (
    <React.Fragment>
      <h5 style={{ marginBottom: "1rem", textAlign: "left" }}>
        You selected:{" "}
        <span style={{ color: "dodgerblue", fontWeight: "800" }}>
          {selectedPet
            ? `${selectedPet?.name} ${selectedPet?.img}`
            : "Nothing yet"}
        </span>
      </h5>
      <Autocomplete
        style={{ width: "40%" }}
        options={pets}
        getOptionLabel={(option) => option.name}
        renderOption={(props, option) => (
          <Box component='li' {...props}>
            {option.name} {option.img}
          </Box>
        )}
        onChange={(event, newPet) => {
          setSelectedPet(newPet);
        }}
        inputValue={petInputValue}
        onInputChange={(event, newPetInputValue) => {
          setPetInputValue(newPetInputValue);
        }}
        renderInput={(params) => {
          return <TextField label='Select your favourite pet' {...params} />;
        }}
      ></Autocomplete>
    </React.Fragment>
  );
};

The above complete component will function as shown below:

As demonstrated above, the selectedPet will return an object of the selected pet from the dropdown and we render the name and img in the dom and the whole object in the browser’s console.

Wrapping Up

In this article, we discussed how to use the React Material UI Autocomplete to display the possible values in a search component. You’ve also learned how to create an MUI autocomplete component, set its default value, and retrieve the component’s selected values.

We hope you found this article useful in understanding the React Material UI Autocomplete and how to use it in your own applications.

You can also learn how to customize and render asynchronous request data as options in the Material UI Autocomplete component from the video below:

Finally, more articles like this are on our CopyCat blog. CopyCat converts your Figma files into a ready-to-use React project, saving you over 35% of development time. You can check out CopyCat here.

Interesting Reads From Our Blogs

  • Creating Tooltips in React with React-Tooltip Library
  • A Guide to Understanding Tricky React setState in Simple Terms
  • Top 17 VSCode Plugins to Boost Productivity as a Developer

Happy Coding 👨🏽‍💻

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement. We’ll occasionally send you account related emails.

Already on GitHub?
Sign in
to your account


Open

nihil-pro opened this issue

Nov 17, 2021

· 23 comments

Comments

@nihil-pro

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

I get an «value provided to Autocomplete is invalid» error:

None of the options match with `{"id":18877,"YearFrom":2002,"YearTo":2005,"Make":"Hyundai","Model":"Getz","Generation":"I (2002—2005)","FuelType":"Бензин","DriveType":"Передний","Transmission":"Автомат","Modification":"1.4 AT (97 л.с.)","Power":97,"EngineSize":"1.4","BodyType":"Хетчбэк","Doors":"5"}`.
You can use the `isOptionEqualToValue` prop to customize the equality test.

Expected behavior 🤔

Well, if i use the isOptionEqualToValue={(option, value) => option.id === value.id}, the expected behavior is that I shouldn’t get an error.

Steps to reproduce 🕹

Steps:

  1. Use Autocomplete:
<Autocomplete
        multiple
        fullWidth
        filterSelectedOptions
        defaultValue={defaultValues}
        options={options}
        isOptionEqualToValue={(option, value) => option.id === value.id}
        getOptionLabel={(option: ICar) =>
          `(${option.id}) 
          ${option.Make} ${option.Model} ${option.Generation} 
          ${option.EngineSize} л ${option.FuelType?.toLowerCase()} ${option.Power} л.с. – ${option.Transmission?.toLowerCase()} ${option.DriveType?.toLowerCase()} привод
          `
        }
        renderInput={(params: AutocompleteRenderInputParams) => <TextField {...params} label={'Применяемость'} />}
        renderOption={(props, option: ICar) => {
          return (
            <li {...props}>
              {option.Make} {option.Model} {option.Generation} {option.EngineSize} л {option.FuelType?.toLowerCase()} {option.Power} л.с. – {option.Transmission?.toLowerCase()} {option.DriveType?.toLowerCase()} привод
            </li>
          )
        }}
        onChange={(_, value) => onChange(value)}
        onInputChange={(event, value) => {
          if (value && value.length >= 3) {
            search(value).finally()
          }
        }}
 />
  1. The defaultValue is also a type Array
  2. I get an error with defaulValue options only

Context 🔦

No response

Your environment 🌎

`npx @mui/envinfo`

 System:
    OS: macOS 12.0.1
  Binaries:
    Node: 16.9.1 - /usr/local/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.6 - ~/node_modules/.bin/npm
  Browsers:
    Chrome: 96.0.4664.45
    Edge: Not Found
    Firefox: 94.0.1
    Safari: 15.1
  npmPackages:
    @emotion/react: ^11.4.1 => 11.4.1 
    @emotion/styled: ^11.3.0 => 11.3.0 
    @mui/core:  5.0.0-alpha.50 
    @mui/icons-material: ^5.0.3 => 5.0.3 
    @mui/material: ^5.0.3 => 5.0.3 
    @mui/private-theming:  5.0.1 
    @mui/styled-engine:  5.0.1 
    @mui/styles:  5.0.1 
    @mui/system:  5.0.3 
    @mui/types:  7.0.0 
    @mui/utils:  5.0.1 
    @mui/x-data-grid: ^5.0.0-beta.3 => 5.0.0-beta.3 
    @types/react: ^17.0.20 => 17.0.20 
    react: ^17.0.2 => 17.0.2 
    react-dom: ^17.0.2 => 17.0.2 
    typescript: ^4.4.3 => 4.4.3 

@michaldudak

@michaldudak
michaldudak

changed the title
The value provided to Autocomplete is invalid. (with the installed isOptionEqualToValue)

[Autocomplete] The value provided to Autocomplete is invalid. (with the installed isOptionEqualToValue)

Nov 17, 2021

@nihil-pro

@michaldudak

Sorry for the late response. I’m getting a 404 error on the sandbox you provided. Could you check it?

@markedwards

I have this issue as well, and I think its the same case. It can happen when implementing an external async search. The Autocomplete component still has a value, but the options are now populated with the results from the search, which does not include the current value.

Here is a reproduction: https://codesandbox.io/s/asynchronous-material-demo-forked-q0yox?file=/demo.tsx

Steps to repro:

  1. type «inter» in the Autocomplete, chose «Interstellar»
  2. deselect the Autocomplete
  3. select the Autocomplete, type «godfather»
  4. observe console

It doesn’t repro 100% of the time, but its pretty easy to get it to happen.

@markedwards

@michaldudak

Thanks for the reproduction, @markedwards. I’m reopening the issue.

@tumetus

I’m experiencing this problem too. Great to see that this issue is opened!

@mcsimps2

Also ran into this issue while fetching autocomplete options from the Google Maps Places API and my own backend. I tried to work around the issue by clearing out the value prop when the inputValue changed since any change in inputValue changes the options prop with new API results. This makes the warning go away but results in a clunky user behavior where it takes 2 keystrokes to start a new «search» instead of one. For some reason, the first one keystroke disappears into oblivion. (E.g. if you highlight the text and then try to replace it by typing, your first key stroke only clears the text and doesn’t place any actual letters into the TextField.) It sounds like some order of operations problem so I didn’t poke in further.

Open to suggestions for other ways to avoid the warning or if it’s okay to just to ignore it overall.

@bsides

Could we please get an option to turn off the warning completely? At this stage it’s causing a lot of noise in tests and, as reported, it’s not warning anything useful.

aidooon, bbauer02, emko, colinscruggs, Vallo, ahmadichsan, MuhammadAlbab, bryantobing12, XTVB, elVengador, and 15 more reacted with thumbs up emoji

@bbauer02

I have the same Issue … boring warning

@michaldudak

Apparently, at this point, the warning causes more confusion than assistance. If anyone is willing to investigate if this warning can be disabled for cases of async loading without much hassle, then feel free to grab this issue.

I’m also considering removing the warning altogether, but let’s try the less destructive option first.

janusch, colinscruggs, ariel-upstream, Vallo, ahmadichsan, p1e7r0, illich570, bryantobing12, iron-cherep, and andreaswilli reacted with thumbs up emoji
colinscruggs, ariel-upstream, and Victor-Villacis reacted with hooray emoji

@angrybacon

In case anyone stumbles upon this issue today still, the trick for async-populated options is to add the currently selected option so that it doesn’t trigger the false positive that can happen when setting a new value while an async request changes the array of options that is provided.

const [item, setItem] = useState<ItemModel>();
const [items, setItems] = useState<ItemModel[]>([]);
const [input, setInput] = useState('');
const query = useDebounce(input, 250);

useEffect(() => {
  fetchItems(query).then((items) => setItems(items));
}, [query]);

return (
  <Autocomplete
    autoComplete
    filterSelectedOptions
    getOptionLabel={(option) => option.name}
    onInputChange={(_event, value) => setInput(value)}
    onChange={(_event, value) => setItem(value)}
    options={item ? [item, ...items] : items}
    renderInput={(extra) => <TextField {...extra} label="Name" />}
  />
);

@bryantobing12

still an issue for me. not wanting to add more state as said in @angrybacon answer, because i use react hook form mainly to control the state.

 <Controller
  name={"district"}
  control={control}
  render={({ field: { onChange, value } }) => (
    <Autocomplete
      onChange={(e, data) => onChange(data)}
      options={districts.map(({ id, name }) => ({ id, name }))}
      value={value}
      getOptionLabel={(option) => option.name}
      isOptionEqualToValue={(option, newValue) => {
        return option.id === newValue.id;
      }}
      renderInput={(params) => (
        <TextField {...params} placeholder="test" label="test" />
      )}
      onInputChange={(_evt, newValue) => setSearch(newValue)}
      inputValue={search}
    />
  )}
/>

can i just return true for isOptionEqualToValue prop? is it affect anything., didn’t find the effect so far. even still don’t get it the purpose of that prop in the first place

@ianpaschal

I’m currently struggling with this. I’m going to use this comment box as a rubber duck and maybe someone can explain what I’m doing wrong.

So… This error has made me realize I don’t entirely get what the point of the value field is anyway. As I understand it, the autocomplete component is essentially a text input and a select welded together. The onChange handler fires when the user clicks an item à la select, whereas onInputChange and inputValue are for the text input portion.

From what I can see, the both the text input and the selection set the value, which makes sense because while there’s only one value for the component, even if there’s two ways to set it.

I’ve been storing my value in a hook, and passing it back in to both value and inputValue and getting this warning (even though everything works fine). I figured it’s because value expects some item in my options array (such as an {label: string; id: string;}). So I tried storing the value separately (as the docs do indeed suggest), but that:

  1. Does not suppress the warning (it just complains now that the object doesn’t match either).
  2. Causes the typed input to be over-written by the last select value.

The latter I suppose can be mitigated by unsetting the «select value» when the user modifies the input text and falling back to value={inputValue} but that raises the question, «Why set it to anything besides inputValue in the first place?»

So, am I doing something wrong or is this warning truly just meaningless? I feel like I must be doing something wrong because surely the value prop is not as useless as it appears to be?

I think for now I will just use a <Select /> instead of <Autocomplete />. I’ll miss the nice filtering/instant search but I don’t really want a component like this where I can’t figure out from the documentation how it’s supposed to be used and which spews out console warnings in my production code base. 😞

As a closing note, if my intuitions are correct, I’d argue the naming of the Autocomplete props is rather misleading/confusing. The text field value should be called value and have its onChange property, and there should be another prop called onSelect or ‘onComplete` which is used for when the value is set by via autocomplete behavior.

Thoughts?

@ianpaschal

I forked the controlled input example from the documentation and tweaked it slightly, working towards what I was actually building (albeit not for Harry Potter characters).

Although the warning does not show up, there is a lot of questionable UX going on. You will notice the behavior where you delete half the name and it reappears on blur because of the odd implementation choice of having the Autocomplete have two values.

I’ve «solved» that by setting value via the onInputChange handler, which removes the need for two pieces of state, and removes the weird ambiguity between the two competing/conflicting values. But the documentation explicitly advises against this.

Of course, creating this dummy value object does make it clear why the warning shows up.

Which would bring me back to: Either the Autocomplete component should be completely re-thought (probably the «right» solution) w.r.t. multiple values and setters, OR the warning should be ditched and you can set the value to whatever you want.

The latter also does feel like a «right» choice considering entering non-specific options is kind of the whole thing that sets <Autocomplete /> apart from <Select />. If you don’t want the user to be able to type in random other text, use a <Select />, no?

@LeVraiNinjaneer

Got same issue. Too bad there’s no solution yet, but glad that it’s on the radar.

@shinsou

I had a bit different kind of a problem that is described in this thread, but as it lands on same field I decided to post here rather to post new thread (hope that’s fine).

TL;DR

A opinion that has very minor affect on… anything. May resolve some common issues found in internet with this component.

Decription

I have MUIv5 and I use MUI Autocomplete, with Formik (with Yup) and use typescript. I’ve come into an opinion where I feel like that useAutocomplete (@mui/base/AutocompleteUnstyled/useAutocomplete.js) applies bad practices.

By the snipped code below, it states that the Autocomplete initial value can not be undefined, but rather null?
— henche, to my knowledge undefined is stated as «not set» or in validation schemes «not touched» and null is actually a defined value («someone or something have changed or set it’s value to null).

In my case this caused the form to be initialized with «undefined»… string (what the …) and bunch of error/warning messages, saying:

  • Material-UI: the value provided to Autocomplete is invalid. None of the options match with ´""´.
  • The getOptionLabel method of Autocomplete returned undefined instead of a string for "".
  if (process.env.NODE_ENV !== 'production') {
    if (value !== null && !freeSolo && options.length > 0) { // <-----------
      const missingValue = (multiple ? value : [value]).filter(value2 => !options.some(option => isOptionEqualToValue(option, value2)));

      if (missingValue.length > 0) {
        console.warn([`MUI: The value provided to ${componentName} is invalid.`, `None of the options match with `${missingValue.length > 1 ? JSON.stringify(missingValue) : JSON.stringify(missingValue[0])}`.`, 'You can use the `isOptionEqualToValue` prop to customize the equality test.'].join('n'));
      }
    }
  }

Curtain call

I resolved my problem by initializing form values with null and applying nullable into Yup validation schema for the fields.

Sample code:

<Field
    name="fieldName"
    component={Autocomplete}
    options={sortedfieldNameKeys}
//    getOptionLabel={(option: string) => sortedfieldNameKeys?.length > 0 ? fields[option] : "" }
    getOptionLabel={(option: string) => sortedfieldNameKeys?.length > 0 ? fields[option] : null }
    renderInput={(params: AutocompleteRenderInputParams) => (
        <MuiTextField
            {...params}
            name="fieldName"
            label={translator('fieldName')}
            variant="standard"
            helperText={touched?.fieldName && errors.fieldName && errors.fieldName}
            error={touched?.fieldName && Boolean(errors.fieldName)}
        />
    )}
    sx={{ width: '20ch', mr: 4 }}
/>
// ....
=> fields = await getFields(); // [ { "01aeed68-...", value: "Field 1" }, { "470401eb-...", value: "Field 2" },... ]
// ....
=> sortedFieldNameKeys = Object.entries(fields).map(({key, value}) => (key));
// ....
=> form = {
  ...,
  fieldName: null, // '' // undefined  ... oof
}

@parulraheja98

Is there any update on this? Still able to reproduce this issue locally. @michaldudak

@monika-parmar

I’m facing this warning everytime when I try to select a link, that I’ve provided in dropdown, with the help of paper component.
I’m sharing the Autocomplete component and the UI screenshot of the dropdown
<Autocomplete popupIcon={''} fullWidth clearOnBlur clearOnEscape sx={[ error.fullAddress ? commonClasses.fieldError : {}, onboardingStyle.searchAddressAutocomplete, ]} loading={isOnboardingFormAddressLookUpSearchLoaderActive} disableClearable={!!searchAddressValue} value={onboardingForm.fullAddress} data-testid={ON_BOARDING_TEST_CONSTANTS.ADDRESS} options={searchAddressResults} PaperComponent={(paperComponentProps) => ( <SearchAddressDropdown paperComponentProps={paperComponentProps} onboardingForm={onboardingForm} setOnboardingForm={setOnboardingForm} setIsAddressModalOpen={setIsAddressModalOpen} /> )} noOptionsText={ searchAddressValue?.length > 2 ? 'No search results found' : 'Search address..' } renderInput={(params) => ( <TextField onChange={debounceSearch} {...params} label='ADDRESS' InputProps={{ ...params.InputProps, type: 'search', }} helperText={error?.fullAddress} /> )} onChange={onOptionChange} />
image
image

@tomkingkong

For anyone who may still be running into this warning. The issue I ran into was a mislabelling of «freeSolo», with a capital «S».

@jjrmunoz

I have got the same issue — getting the warning: «The value provided to Autocomplete is invalid. None of the options match with «». You can use the isOptionEqualToValue prop to customize the equality test».

Adding the final part || value === "" to isOptionEqualToValue={(option, value) => option.name === value.name || value === "" removes the warning, but then a new problem appears: all options turn colored as if all were chosen

@vuhi

I have multi select AutoComplete. This is the way I solve the problem:

  • options: <[{ label, value, type }]>
  • Turn on freeSolo, autoSelect to ignore warning
  • Turn on clearOnBlur to ignore value that not [Enter] or throw selecting an option in dropdown
  • Modify onChange to handle unwanted text
<Autocomplete
      freeSolo
      disabled={loading}
      multiple
      clearOnBlur
      options={options}
      getOptionLabel={(option) => option.label}
      groupBy={(option) => option.type}
      /** Help show no option dropdown, freeSolo does not show it **/
      getOptionDisabled={(option) => option.label && option.label.toLowerCase() === 'no option'}
      filterOptions={() => {
        if (!options.length) return [{ label: 'No option', value: 'No option' }];
        return options;
      }}
      value={selectedOptions}
      onChange={(event, selectedValues) => {
          // This only apply to multi select
          if (['removeOption', 'clear'].includes(reason)) {
              setSelectedOptions(selectedValues);
          }
          if (['selectOption'].includes(reason)) {
              const lastValue = [...multiValue].pop();
              const isAllow = options.some((item) => item.label === lastValue?.label);
              if (!isAllow) break;
              setSelectedOptions(multiValue);
          }
      }}
      onInputChange={(event, value) => setSearchTerm(value)}
      renderInput={(params) => (
          <TextField {...params} label="label" />
      )}
/>

Happy coding :)

@derekcannon

While freesolo may work to solve this issue, it seems like a workaround for a common use case. Using multi-select with server-side search is a common pattern that shouldn’t trigger a warning.

Perhaps there should be a prop to signify «Search as you type» (as the Docs refers to it) that does not allow for free entry but does allow for items to exist in the values that don’t exist in the current options and, by default, disables filterOptions (instead of having to set filterOptions={(x) => x} as the Docs recommends).

Понравилась статья? Поделить с друзьями:
  • Mugen error sans
  • Mugen error detected
  • Mugen characters error
  • Mugen archive error 1020
  • Mudrunner ошибка установки