Skip to content

[Autocomplete] Fix auto highlight when options change but not the length #46489

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
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

yafeng-c
Copy link

@yafeng-c yafeng-c commented Jul 5, 2025

Fixes #33634

Before: https://stackblitz.com/edit/github-cfngmona-qpp5b5ev
After: https://stackblitz.com/edit/github-cfngmona-urwg9d2g


Fixes #45279

Before: https://stackblitz.com/edit/github-cfngmona
After: https://stackblitz.com/edit/github-cfngmona-azw9frdq


I think it is due to the dependency filteredOptions.length of syncHighlightedIndex. Since the new options have the same length just elements order change, it will not sync highlight with the new options.

Tracing back this condition, looks like if we simply change it to filteredOptions, it might reintroduce some other errors,(ref: #21280 and #19923). On the other hand, since options are indeed different, so this PR tries to make useEffect with syncHighlightedIndex listen to the change of options. With the deps of syncHighlightedIndex not changed, old issue should not be brought back.

I have added some unit tests and this playground file could also be used to test locally.

After

Jul-05-2025 16-32-06

@mui-bot
Copy link

mui-bot commented Jul 5, 2025

Netlify deploy preview

https://deploy-preview-46489--material-ui.netlify.app/

Bundle size report

Bundle Parsed Size Gzip Size
@mui/material 🔺+168B(+0.03%) 🔺+77B(+0.05%)
@mui/lab 🔺+167B(+0.13%) 🔺+105B(+0.26%)
@mui/system 0B(0.00%) 0B(0.00%)
@mui/utils 0B(0.00%) 0B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against 91a5b21

@yafeng-c yafeng-c force-pushed the autocomplete-45279 branch from cdd33f8 to 8744a12 Compare July 5, 2025 15:10
@@ -465,8 +480,11 @@ function useAutocomplete(props) {

if (
highlightedIndexRef.current !== -1 &&
previousProps.filteredOptions &&
previousProps.filteredOptions.length !== filteredOptions.length &&
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strengthen this condition by checking if elements are the same.

@yafeng-c yafeng-c marked this pull request as ready for review July 5, 2025 15:35
@zannager zannager added the component: autocomplete This is the name of the generic UI component, not the React module! label Jul 7, 2025
@zannager zannager requested a review from mj12albert July 7, 2025 10:14
@ZeeshanTamboli ZeeshanTamboli changed the title [Autocomplete] fix auto highlight when options change but not the length [Autocomplete] Fix auto highlight when options change but not the length Jul 12, 2025
@ZeeshanTamboli ZeeshanTamboli added the bug 🐛 Something doesn't work label Jul 12, 2025
Copy link
Member

@ZeeshanTamboli ZeeshanTamboli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yafeng-c Thanks for the PR!

This also fixes #45279 — I’ve updated the PR description with before/after repros.

For #33634 (see https://stackblitz.com/edit/github-cfngmona-urwg9d2g), I need to press Arrow Down twice to reach the options.

Also, can we avoid the flash when the listbox updates but the highlight stays on the first option?

@yafeng-c
Copy link
Author

For #33634 (see https://stackblitz.com/edit/github-cfngmona-urwg9d2g), I need to press Arrow Down twice to reach the options.

Nice catch. I reproduced this issue by first typing, for example 0, then pressing arrow down, it did not hight light the second option although the highlighted value was updated. This was caused by filteredOptionsChanged. When first typing 0, filteredOptionsChanged became true; when pressing arrow down, filteredOptionsChanged became false, then triggering syncHighlightedIndex. I took an another look of syncHighlightedIndex, it feels like it should only be triggered when filteredOptionsChanged is true. All tests passed.

can we avoid the flash when the listbox updates but the highlight stays on the first option?

If I understand the issue correctly, I reproduced it with https://stackblitz.com/edit/github-cfngmona-urwg9d2g. When updating from pediatri to pediatric. I could see the flash but I feel it is expected because the highlight moves from pediatric ent to pediatrician, so it is caused by the highlight movement?

Copy link
Member

@ZeeshanTamboli ZeeshanTamboli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. But I would like a final review from others in case I missed something. cc @DiegoAndai

OrangeDoro

This comment was marked as off-topic.

array1 &&
array2 &&
array1.length === array2.length &&
array1.every((prevOption, index) => parser(prevOption) === parser(array2[index]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to invert the logic using array.some for better performance?

if array1 is large, says >300 it could introduce performance issue.

Copy link
Author

@yafeng-c yafeng-c Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I ask what's the specific solution you are suggesting?
if you mean !array1.some((prevOption, index) => parser(prevOption) !== parser(array2[index])), I don't think there will be improvement:

  1. if two array length are different then line 15 will not execute.
  2. every will return false and stop iterating immediately once a false returned in callback.
  3. if the two arrays are the same, some will still iterate the whole array1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: autocomplete This is the name of the generic UI component, not the React module!
Projects
None yet
6 participants