Skip to content

fix(tag-picker): keep dropdown list aligned during parent container motion#36376

Open
PaulGMardling wants to merge 10 commits into
microsoft:masterfrom
PaulGMardling:fix/tagpicker-dialog-misalignment
Open

fix(tag-picker): keep dropdown list aligned during parent container motion#36376
PaulGMardling wants to merge 10 commits into
microsoft:masterfrom
PaulGMardling:fix/tagpicker-dialog-misalignment

Conversation

@PaulGMardling

@PaulGMardling PaulGMardling commented Jul 8, 2026

Copy link
Copy Markdown

Implementation Notes

I considered 3 paths to fix the stale position on reopen issue:

  1. Dialog-side signal (rejected).
    Expose a callback/state for when the Dialog entry animation finishes and defer rendering positioned content until it settles. Changes the Dialog API, pushes work onto every consumer, and only solves the dialog case.
  2. One-shot recalculation on animation end (rejected).
    Listen for animationend/transitionend on the ancestor and force a single update. Fragile: DialogSurface animates via the Web Animations API (no reliable transitionend), you have to guess which ancestor to watch, and the popover stays misaligned during the animation before snapping into place.
  3. Opt-in per-frame updates in react-positioning (chosen).
    Add an updatePositionOnAnimationFrame option to the shared position manager that re-evaluates position each frame while mounted, so the popover tracks its target regardless of what moved it. TagPicker opts in; everything else is unaffected.

I chose this solution because it's the smallest and most robust change. It defaults to false (no behavior change for existing components — only TagPicker enables it), and keeps the dropdown aligned throughout the animation rather than only after it ends. Because it's a general option on react-positioning rather than a Dialog - or TagPicker - specific hack, any positioned component that hits the same class of problem — a target moved by ancestor animation, transforms, or other motion that doesn't trigger scroll/resize observers — can opt in with a single flag instead of reimplementing the workaround.

Previous Behavior

Opening a TagPicker popover inside a Dialog could produce incorrect popup alignment after dialog reopen when content is rendered during dialog entry motion. The popup position could be computed from transient animated geometry and remain offset.

575848807-53749281-be36-4af8-a799-c7d5d3c136a2

New Behavior

TagPicker popover positioning now stays aligned with its trigger even when opened inside an animating Dialog surface. Positioning updates are refreshed during animation frames for this scenario, preventing stale offset coordinates on reopen.

Screen.Recording.2026-07-09.at.11.06.37.mov

Added/updated coverage:

  1. react-positioning unit coverage for animation-frame update behavior in createPositionManager.
  2. TagPicker Cypress regression coverage for dialog reopen alignment behavior.

Related Issue(s)

Fixes #35968

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-charts
AreaChart
404.33 kB
126.47 kB
404.556 kB
126.538 kB
226 B
68 B
react-charts
DeclarativeChart
754.979 kB
221.561 kB
755.205 kB
221.628 kB
226 B
67 B
react-charts
DonutChart
315.101 kB
97.163 kB
315.327 kB
97.221 kB
226 B
58 B
react-charts
FunnelChart
306.342 kB
93.907 kB
306.568 kB
93.977 kB
226 B
70 B
react-charts
GanttChart
387.387 kB
120.871 kB
387.613 kB
120.942 kB
226 B
71 B
react-charts
GaugeChart
314.434 kB
96.549 kB
314.66 kB
96.612 kB
226 B
63 B
react-charts
GroupedVerticalBarChart
395.541 kB
123.696 kB
395.767 kB
123.771 kB
226 B
75 B
react-charts
HeatMapChart
389.495 kB
121.928 kB
389.721 kB
121.993 kB
226 B
65 B
react-charts
HorizontalBarChart
294.867 kB
89.75 kB
295.093 kB
89.818 kB
226 B
68 B
react-charts
Legends
234.403 kB
70.457 kB
234.629 kB
70.532 kB
226 B
75 B
react-charts
LineChart
415.681 kB
129.6 kB
415.907 kB
129.664 kB
226 B
64 B
react-charts
PolarChart
343.354 kB
107.407 kB
343.58 kB
107.477 kB
226 B
70 B
react-charts
SankeyChart
212.023 kB
68.066 kB
212.249 kB
68.146 kB
226 B
80 B
react-charts
ScatterChart
395.007 kB
123.647 kB
395.233 kB
123.709 kB
226 B
62 B
react-charts
VerticalBarChart
431.939 kB
128.619 kB
432.165 kB
128.697 kB
226 B
78 B
react-charts
VerticalStackedBarChart
401.559 kB
125.101 kB
401.785 kB
125.174 kB
226 B
73 B
react-combobox
Combobox (including child components)
137.959 kB
44.618 kB
138.185 kB
44.694 kB
226 B
76 B
react-combobox
Dropdown (including child components)
137.715 kB
44.382 kB
137.941 kB
44.47 kB
226 B
88 B
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
225.836 kB
67.998 kB
226.062 kB
68.063 kB
226 B
65 B
react-components
react-components: entire library
1.293 MB
325.78 kB
1.293 MB
325.874 kB
260 B
94 B
react-datepicker-compat
DatePicker Compat
216.034 kB
63.912 kB
216.26 kB
63.987 kB
226 B
75 B
react-menu
Menu (including children components)
159.561 kB
50.654 kB
159.787 kB
50.72 kB
226 B
66 B
react-menu
Menu (including selectable components)
162.727 kB
51.291 kB
162.953 kB
51.356 kB
226 B
65 B
react-popover
Popover
125.312 kB
40.384 kB
125.538 kB
40.459 kB
226 B
75 B
react-positioning
usePositioning
28.795 kB
10.14 kB
29.021 kB
10.221 kB
226 B
81 B
react-tag-picker
@fluentui/react-tag-picker - package
173.82 kB
54.128 kB
174.08 kB
54.208 kB
260 B
80 B
react-teaching-popover
TeachingPopover
100.504 kB
31.752 kB
100.73 kB
31.835 kB
226 B
83 B
react-timepicker-compat
TimePicker
140.677 kB
45.99 kB
140.903 kB
46.073 kB
226 B
83 B
react-tooltip
Tooltip
53.023 kB
18.833 kB
53.249 kB
18.913 kB
226 B
80 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-avatar
Avatar
47.22 kB
14.855 kB
react-avatar
AvatarGroup
16.254 kB
6.502 kB
react-avatar
AvatarGroupItem
60.339 kB
18.758 kB
react-breadcrumb
@fluentui/react-breadcrumb - package
103.012 kB
28.827 kB
react-charts
HorizontalBarChartWithAxis
63 B
83 B
react-charts
Sparkline
80.888 kB
26.864 kB
react-checkbox
Checkbox
29.609 kB
10.527 kB
react-components
react-components: Button, FluentProvider & webLightTheme
66.281 kB
19.002 kB
react-components
react-components: FluentProvider & webLightTheme
39.504 kB
13.112 kB
react-dialog
Dialog (including children components)
89.951 kB
27.858 kB
react-field
Field
21.132 kB
7.881 kB
react-headless-components-preview
react-headless-components-preview: entire library
247.532 kB
71.414 kB
react-input
Input
25.027 kB
8.183 kB
react-list
List
74.531 kB
23.01 kB
react-list
ListItem
98.023 kB
29.881 kB
react-overflow
hooks only
9.053 kB
3.227 kB
react-persona
Persona
54.173 kB
16.791 kB
react-portal-compat
PortalCompatProvider
5.341 kB
2.146 kB
react-positioning
useSafeZoneArea
12.399 kB
4.977 kB
react-progress
ProgressBar
19.063 kB
7.418 kB
react-radio
Radio
26.994 kB
8.711 kB
react-radio
RadioGroup
12.759 kB
5.176 kB
react-select
Select
24.876 kB
8.936 kB
react-slider
Slider
32.231 kB
11.086 kB
react-spinbutton
SpinButton
32.513 kB
10.584 kB
react-swatch-picker
@fluentui/react-swatch-picker - package
92.187 kB
27.315 kB
react-switch
Switch
32.231 kB
10.156 kB
react-table
DataGrid
146.759 kB
43.576 kB
react-table
Table (Primitives only)
36.893 kB
12.305 kB
react-table
Table as DataGrid
118.503 kB
33.331 kB
react-table
Table (Selection only)
65.373 kB
18.591 kB
react-table
Table (Sort only)
64.036 kB
18.204 kB
react-tags
InteractionTag
12.463 kB
4.942 kB
react-tags
Tag
28.376 kB
8.9 kB
react-tags
TagGroup
69.648 kB
21.404 kB
react-textarea
Textarea
23.392 kB
8.447 kB
react-tree
FlatTree
135.571 kB
40.413 kB
react-tree
PersonaFlatTree
137.417 kB
40.931 kB
react-tree
PersonaTree
133.498 kB
39.718 kB
react-tree
Tree
131.658 kB
39.221 kB
🤖 This report was generated against bc5035bfcd53277a39075c596b14b9731020d1de

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

Pull request demo site: URL

@PaulGMardling

Copy link
Copy Markdown
Author

@PaulGMardling please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

@microsoft-github-policy-service agree company="Microsoft"

@microsoft microsoft deleted a comment from github-actions Bot Jul 9, 2026
@@ -0,0 +1,106 @@
import * as React from 'react';

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This file will be removed before merging.

It was used to demo the changes locally

@microsoft microsoft deleted a comment from github-actions Bot Jul 9, 2026
@PaulGMardling PaulGMardling changed the title fix(tag-picker): keep popup aligned during dialog motion fix(tag-picker): keep dropdown list aligned during dialog motion Jul 10, 2026
@PaulGMardling PaulGMardling force-pushed the fix/tagpicker-dialog-misalignment branch from 5a868e9 to 56b1d30 Compare July 10, 2026 12:39
@@ -0,0 +1,7 @@
{

@github-actions github-actions Bot Jul 10, 2026

Copy link
Copy Markdown

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/CalendarCompat 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/CalendarCompat.multiDayView.default.chromium.png 843 Changed
vr-tests-react-components/CalendarCompat.multiDayView.default.chromium_1.png 849 Changed
vr-tests-react-components/CalendarCompat.multiDayView - High Contrast.default.chromium.png 3317 Changed
vr-tests-react-components/CalendarCompat.multiDayView - Dark Mode.default.chromium.png 3282 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 965 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 729 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 square - Dark Mode.default.chromium.png 2 Changed
vr-tests-react-components/TagPicker 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - RTL.disabled input hover.chromium.png 635 Changed

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

@PaulGMardling PaulGMardling marked this pull request as ready for review July 10, 2026 13:32
@PaulGMardling PaulGMardling requested a review from a team as a code owner July 10, 2026 13:32
@PaulGMardling PaulGMardling changed the title fix(tag-picker): keep dropdown list aligned during dialog motion fix(tag-picker): keep dropdown list aligned during parent container motion Jul 13, 2026
@PaulGMardling PaulGMardling force-pushed the fix/tagpicker-dialog-misalignment branch from 56b1d30 to fe08ac5 Compare July 13, 2026 08:18
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.

[Bug]: TagPicker dropdown misaligned when opened inside Dialog with entry animation

1 participant