Skip to content

fix(react-popover): omit role='group' from PopoverSurface when no accessible name is provided#36383

Draft
PaulGMardling wants to merge 5 commits into
microsoft:masterfrom
PaulGMardling:fix/a11y-popover-default
Draft

fix(react-popover): omit role='group' from PopoverSurface when no accessible name is provided#36383
PaulGMardling wants to merge 5 commits into
microsoft:masterfrom
PaulGMardling:fix/a11y-popover-default

Conversation

@PaulGMardling

Copy link
Copy Markdown

Decision needed

The bug's full expected result is that Narrator announces the popover contents on activation, not just stops saying the wrong thing.

The Popover component already has auto-focus logic — it focuses the surface if tabIndex is set, or the first interactive element inside it.

The gap is when a consumer passes non-interactive content with no tabIndex={-1} on the surface: focus never leaves the trigger and Narrator never reads the content so the user is left lost without feedback

The component cannot know what content is passed in, so this cannot be solved at the component level without risking regressions in other scenarios.

The decision needed is:
Do we push consumers to handle this via guidance and documentation, or do we make a component-level change?

This needs input from the code owners before the ticket can be closed.

Previous Behavior

On activating a popover with no interactive elements, Narrator announces, 'contains style group'.

New Behavior

PopoverSurface no longer applies role='group' unconditionally when is false.
The role is now only set when the consumer provides an accessible name via aria-label or aria-labelledby — matching the WAI-ARIA 1.2 requirement that group must have an accessible name. Without one, the surface renders as a plain div, so Narrator no longer announces "contains style group" when activating a non-modal popover.

Implementation Details

The aria attribute logic has been extracted into a pure function getPopoverSurfaceAriaAttributes to allow isolated unit testing independent of the hook.

The default Popover story has been updated to include aria-label as the recommended usage pattern.

Note for discussion:

This fix stops the incorrect announcement. The broader expected result — Narrator automatically reading the popover text content on open — requires a follow-up decision on focus management vs aria-live.
UX input is needed before that work proceeds.

Fixes

https://dev.azure.com/microsoftdesign/fluent-ui/_workitems/edit/18661

@PaulGMardling PaulGMardling changed the title Fix/a11y popover default fix(react-popover): omit role='group' from PopoverSurface when no accessible name is provided Jul 10, 2026
@github-actions

Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-charts
AreaChart
404.33 kB
126.47 kB
404.463 kB
126.536 kB
133 B
66 B
react-charts
DeclarativeChart
754.979 kB
221.561 kB
755.112 kB
221.609 kB
133 B
48 B
react-charts
DonutChart
315.101 kB
97.163 kB
315.234 kB
97.217 kB
133 B
54 B
react-charts
FunnelChart
306.342 kB
93.907 kB
306.475 kB
93.955 kB
133 B
48 B
react-charts
GanttChart
387.387 kB
120.871 kB
387.52 kB
120.92 kB
133 B
49 B
react-charts
GaugeChart
314.434 kB
96.549 kB
314.567 kB
96.613 kB
133 B
64 B
react-charts
GroupedVerticalBarChart
395.541 kB
123.696 kB
395.674 kB
123.748 kB
133 B
52 B
react-charts
HeatMapChart
389.495 kB
121.928 kB
389.628 kB
121.979 kB
133 B
51 B
react-charts
HorizontalBarChart
294.867 kB
89.75 kB
295 kB
89.82 kB
133 B
70 B
react-charts
LineChart
415.681 kB
129.6 kB
415.814 kB
129.651 kB
133 B
51 B
react-charts
PolarChart
343.354 kB
107.407 kB
343.487 kB
107.458 kB
133 B
51 B
react-charts
SankeyChart
212.023 kB
68.066 kB
212.156 kB
68.118 kB
133 B
52 B
react-charts
ScatterChart
395.007 kB
123.647 kB
395.14 kB
123.695 kB
133 B
48 B
react-charts
VerticalBarChart
431.939 kB
128.619 kB
432.072 kB
128.679 kB
133 B
60 B
react-charts
VerticalStackedBarChart
401.559 kB
125.101 kB
401.692 kB
125.146 kB
133 B
45 B
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
225.836 kB
67.998 kB
225.969 kB
68.05 kB
133 B
52 B
react-components
react-components: entire library
1.293 MB
325.78 kB
1.293 MB
325.859 kB
133 B
79 B
react-popover
Popover
125.312 kB
40.384 kB
125.445 kB
40.436 kB
133 B
52 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-charts
HorizontalBarChartWithAxis
63 B
83 B
react-charts
Legends
234.403 kB
70.457 kB
react-charts
Sparkline
80.888 kB
26.864 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-datepicker-compat
DatePicker Compat
216.034 kB
63.912 kB
react-dialog
Dialog (including children components)
89.951 kB
27.858 kB
react-headless-components-preview
react-headless-components-preview: entire library
247.532 kB
71.414 kB
react-persona
Persona
54.173 kB
16.791 kB
react-portal-compat
PortalCompatProvider
5.341 kB
2.146 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-tag-picker
@fluentui/react-tag-picker - package
173.82 kB
54.128 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-teaching-popover
TeachingPopover
100.504 kB
31.752 kB
react-timepicker-compat
TimePicker
140.677 kB
45.99 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 e75edae32b44d1733e392f420e5dd2d6fa8bfa0d

@github-actions

Copy link
Copy Markdown

Pull request demo site: URL

@@ -0,0 +1,7 @@
{

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/Avatar Converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Avatar Converged.badgeMask.normal.chromium.png 5 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 - RTL.submenus open.chromium.png 404 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 757 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 135 Changed
vr-tests-react-components/ProgressBar converged 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 95 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 67 Changed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant