Skip to content

fix: support external focus management on Combobox and Dropdown#36279

Open
Weffe wants to merge 4 commits into
microsoft:masterfrom
Weffe:expose-activedescendant-ref
Open

fix: support external focus management on Combobox and Dropdown#36279
Weffe wants to merge 4 commits into
microsoft:masterfrom
Weffe:expose-activedescendant-ref

Conversation

@Weffe
Copy link
Copy Markdown

@Weffe Weffe commented Jun 3, 2026

This PR exposes a ref to the activeDescendantImperative api so that consumers can control the focus for Combobox, Dropdown, and Listbox programmatically.

Previous Behavior

If a consumer wanted to move focus to an option, they usually would use the native .focus() api on their target element. This however was a pitfall for Combobox, Dropdown, and Listbox as they own their own focus state for the options via useActiveDescendant. Meaning any attempts at using the .focus() api would get overwritten or seemingly ignored because it's the wrong tool to begin with.

You can see the issue on the Storybook for Combobox + Virtualizer: https://storybooks.fluentui.dev/react/?path=/docs/components-combobox--docs#virtualizer

  1. Open the combobox and select an option far down the list (e.g. Option 500).
  2. Close the combobox
    a. You might have to lose focus by tabbing away and back to the combobox. See GIF.
  3. Reopen the combobox with keyboard
  4. See the virtual window scrolled into view Option 500
  5. Press the down arrow but notice the focus moves to Option 489 for example (it might differ based on viewport size)

The expected behavior there is for it to move the focus down to Option 501. The reason this is occuring is because the virtual window is only rendering into the DOM Options 489-570 for example and there is no way to sync what item to focus in the active descendant.

GIF of buggy behavior

Note: I did notice if you re-open the combobox again, the 2nd time the focus is properly moved.

Screen Recording 2026-06-03 at 12 19 48 PM

New Behavior

Consumers can now use the activeDescendantImperativeRef prop to get at the same underlying focus state and can correctly move focus to a target of their choice.

Going back to the Combobox + Virtualizer example, the consumer would need to update their code so that on open they use the activeDescendantImperativeRef.focus(targetHtmlid) method to sync focus.

Related Issue(s)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Pull request demo site: URL

@@ -0,0 +1,7 @@
{
Copy link
Copy Markdown

@github-actions github-actions Bot Jun 3, 2026

Choose a reason for hiding this comment

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

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Avatar Converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Avatar Converged.badgeMask.normal.chromium.png 4 Changed
vr-tests-react-components/Charts-DonutChart 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic.default.chromium.png 30718 Changed
vr-tests-react-components/Charts-DonutChart.Dynamic - RTL.default.chromium.png 30608 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 600 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 618 Changed
vr-tests-react-components/ProgressBar converged 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 85 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 143 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 121 Changed
vr-tests-react-components/Skeleton converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Skeleton converged.Opaque Skeleton with rectangle - Dark Mode.default.chromium.png 1 Changed
vr-tests-react-components/TagPicker 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - High Contrast.chromium.png 1319 Changed
vr-tests-react-components/TagPicker.disabled - Dark Mode.disabled input hover.chromium.png 658 Changed
vr-tests-react-components/TagPicker.disabled - RTL.disabled input hover.chromium.png 635 Changed
vr-tests-react-components/TagPicker.disabled.chromium.png 677 Changed

There were 4 duplicate changes discarded. Check the build logs for more information.

mnegrete added 2 commits June 3, 2026 09:58
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-combobox
Combobox (including child components)
101.09 kB
33.224 kB
101.184 kB
33.249 kB
94 B
25 B
react-combobox
Dropdown (including child components)
100.858 kB
33.003 kB
100.952 kB
33.018 kB
94 B
15 B
react-components
react-components: entire library
1.295 MB
325.231 kB
1.295 MB
325.249 kB
140 B
18 B
react-headless-components-preview
react-headless-components-preview: entire library
198.183 kB
56.549 kB
198.231 kB
56.57 kB
48 B
21 B
react-tag-picker
@fluentui/react-tag-picker - package
173.769 kB
54.101 kB
173.817 kB
54.114 kB
48 B
13 B
react-timepicker-compat
TimePicker
104.049 kB
34.748 kB
104.143 kB
34.772 kB
94 B
24 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-components
react-components: Button, FluentProvider & webLightTheme
66.328 kB
19.02 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
226.19 kB
67.909 kB
react-components
react-components: FluentProvider & webLightTheme
39.525 kB
13.113 kB
react-portal-compat
PortalCompatProvider
5.567 kB
2.237 kB
🤖 This report was generated against fdf755ce26d41c57452b79fb23fc4a590630a1b5

@Weffe Weffe marked this pull request as ready for review June 3, 2026 19:27
@Weffe Weffe requested review from a team and dmytrokirpa as code owners June 3, 2026 19:27
@dmytrokirpa dmytrokirpa requested a review from bsunderhus June 3, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant