diff --git a/docs/pages/api/autocomplete.md b/docs/pages/api/autocomplete.md
index 573ed86a480c3d..d2077b0bd06121 100644
--- a/docs/pages/api/autocomplete.md
+++ b/docs/pages/api/autocomplete.md
@@ -45,6 +45,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| freeSolo | bool | false | If `true`, the Autocomplete is free solo, meaning that the user input is not bound to provided options. |
| getOptionDisabled | func | | Used to determine the disabled state for a given option. |
| getOptionLabel | func | x => x | Used to determine the string value for a given option. It's used to fill the input (and the list box options if `renderOption` is not provided). |
+| getOptionSelected | func | | Used to determine if an option is selected. Uses strict equality by default. |
| groupBy | func | | If provided, the options will be grouped under the returned string. The groupBy value is also used as the text for group headings when `renderGroup` is not provided.
**Signature:**
`function(options: any) => string`
*options:* The option to group. |
| id | string | | This prop is used to help implement the accessibility logic. If you don't provide this prop. It falls back to a randomly generated id. |
| includeInputInList | bool | false | If `true`, the highlight can move to the input. |
diff --git a/docs/src/pages/components/autocomplete/Asynchronous.js b/docs/src/pages/components/autocomplete/Asynchronous.js
index 191fb07914c2ac..3054441053b7d3 100644
--- a/docs/src/pages/components/autocomplete/Asynchronous.js
+++ b/docs/src/pages/components/autocomplete/Asynchronous.js
@@ -55,6 +55,7 @@ export default function Asynchronous() {
onClose={() => {
setOpen(false);
}}
+ getOptionSelected={(option, value) => option.name === value.name}
getOptionLabel={option => option.name}
options={options}
loading={loading}
diff --git a/docs/src/pages/components/autocomplete/Asynchronous.tsx b/docs/src/pages/components/autocomplete/Asynchronous.tsx
index acd8730746721c..fb9c2d4b5a848c 100644
--- a/docs/src/pages/components/autocomplete/Asynchronous.tsx
+++ b/docs/src/pages/components/autocomplete/Asynchronous.tsx
@@ -59,6 +59,7 @@ export default function Asynchronous() {
onClose={() => {
setOpen(false);
}}
+ getOptionSelected={(option, value) => option.name === value.name}
getOptionLabel={option => option.name}
options={options}
loading={loading}
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
index 02b14e1979135c..991500fc58a886 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
@@ -236,6 +236,7 @@ const Autocomplete = React.forwardRef(function Autocomplete(props, ref) {
freeSolo = false,
getOptionDisabled,
getOptionLabel = x => x,
+ getOptionSelected,
groupBy,
id: idProp,
includeInputInList = false,
@@ -553,6 +554,11 @@ Autocomplete.propTypes = {
* It's used to fill the input (and the list box options if `renderOption` is not provided).
*/
getOptionLabel: PropTypes.func,
+ /**
+ * Used to determine if an option is selected.
+ * Uses strict equality by default.
+ */
+ getOptionSelected: PropTypes.func,
/**
* If provided, the options will be grouped under the returned string.
* The groupBy value is also used as the text for group headings when `renderGroup` is not provided.
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
index d67795e0b62f72..310167c6c7145a 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
@@ -90,6 +90,11 @@ export interface UseAutocompleteProps {
* It's used to fill the input (and the list box options if `renderOption` is not provided).
*/
getOptionLabel?: (option: any) => string;
+ /**
+ * Used to determine if an option is selected.
+ * Uses strict equality by default.
+ */
+ getOptionSelected?: (option: any, value: any) => boolean;
/**
* If provided, the options will be grouped under the returned string.
* The groupBy value is also used as the text for group headings when `renderGroup` is not provided.
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index a8fd29e1aeabaa..95d714e81d4ec9 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -83,6 +83,7 @@ export default function useAutocomplete(props) {
freeSolo = false,
getOptionDisabled,
getOptionLabel = x => x,
+ getOptionSelected = (option, value) => option === value,
groupBy,
id: idProp,
includeInputInList = false,
@@ -239,7 +240,9 @@ export default function useAutocomplete(props) {
options.filter(option => {
if (
filterSelectedOptions &&
- (multiple ? value.indexOf(option) !== -1 : value === option)
+ (multiple ? value : [value]).some(
+ value2 => value2 !== null && getOptionSelected(option, value2),
+ )
) {
return false;
}
@@ -416,7 +419,15 @@ export default function useAutocomplete(props) {
if (multiple) {
const item = newValue;
newValue = Array.isArray(value) ? [...value] : [];
- const itemIndex = value.indexOf(item);
+
+ let itemIndex = -1;
+ // To replace with .findIndex() once we stop IE 11 support.
+ for (let i = 0; i < newValue.length; i += 1) {
+ if (getOptionSelected(item, newValue[i])) {
+ itemIndex = i;
+ }
+ }
+
if (itemIndex === -1) {
newValue.push(item);
} else {
@@ -791,7 +802,9 @@ export default function useAutocomplete(props) {
},
}),
getOptionProps: ({ index, option }) => {
- const selected = multiple ? value.indexOf(option) !== -1 : value === option;
+ const selected = (multiple ? value : [value]).some(
+ value2 => value2 != null && getOptionSelected(option, value2),
+ );
const disabled = getOptionDisabled ? getOptionDisabled(option) : false;
return {