Skip to content

fix(react-headless-components-preview): correct InfoLabel note semantics - #36953

Open
Paul Mardling (PaulGMardling) wants to merge 8 commits into
microsoft:masterfrom
PaulGMardling:paulgmardling-39558-headless-infolabel
Open

Paul Mardling (PaulGMardling) wants to merge 8 commits into
microsoft:masterfrom
PaulGMardling:paulgmardling-39558-headless-infolabel

Conversation

@PaulGMardling

@PaulGMardling Paul Mardling (PaulGMardling) commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Previous Behavior

InfoButton announced a menu while displaying a note. InfoLabel generated redundant, potentially stale aria-owns.

New Behavior

Use <div popover role="note">, aria-haspopup="false", and the existing open-only aria-details link instead of generated ownership. Preserve consumer ARIA, controlled state, and blur behavior. Explicit focus trapping uses a named native dialog. No public API changes.

Related Issue(s)

Validation

All CI checks pass. Local React 17/18/19 suites: 1,302 tests each; InfoLabel browser spec: 9 cases per version. Build, types, lint, and formatting pass.

yarn nx run react-headless-components-preview:test --maxWorkers=1 --workerIdleMemoryLimit=512MB --silent --skipNxCache
# Passed: 89 suites / 1,302 tests.
yarn nx run react-headless-components-preview:e2e --spec=src/components/InfoLabel/InfoLabel.cy.tsx --browser=chrome --headless --skipNxCache
# Passed: 9 cases.

Reproduction and fix verification

Open the verified PR story.

  1. Open a fresh page; click blank preview space, then Tab to the information button.
  2. Enter opens and focuses the note. Inspect: trigger aria-haspopup="false", aria-expanded="true", and aria-details points to the visible DIV/note; wrapper has no generated aria-owns.
  3. Tab focuses “Learn more”; Shift+Tab returns to the trigger. Escape closes the note, retains trigger focus, and clears aria-details. Space reopens it.

Any mismatch fails verification. Checked locally and on the preview on 2026-10-26, macOS/Chrome 155, React 19.2.0; fresh-page and reload checks passed without runtime errors. Screen-reader output is unverified.

Revision-pinned local reproduction

In an authorized task workspace at fixed commit deb9c1e01fb4865a0136bbe723ff845c814aaa77, follow repository Node/Yarn setup, then run from the repository root:

yarn nx run react-headless-components-preview-stories:storybook --port=6029 --ci

Open http://localhost:6029/iframe.html?id=components-infolabel--default&viewMode=story and repeat the steps. The committed fixture is packages/react-components/react-headless-components-preview/stories/src/InfoLabel/InfoLabelDefault.stories.tsx. Local verification skipped already-built dependencies with --excludeTaskDependencies.

Baseline 78a76c1a1cddd0f4c95328cf0d604f5face54ec6 has the menu token, dialog/note mismatch, and generated ownership. Its full manual browser run is unverified; use the same story/command in a separate authorized baseline workspace to compare. Earlier failing-before tests substituted baseline implementation files, not a historical browser deployment. The hosted preview is mutable and has no verified SHA stamp.

Track ownership from controlled open state or the current optional button lifetime. Ignore stale lifetime callbacks, consume defaultOpen once, and delegate dismissal to the shared Popover engine.

Integrated focus dismissal validation remains blocked on PR microsoft#36929 reaching the base. Custom render-function slot key forwarding remains unverified.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3d006ca2-c036-45bf-bac0-93275c5dfe08
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-headless-components-preview
react-headless-components-preview: entire library
269.204 kB
80.184 kB
269.449 kB
80.254 kB
245 B
70 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-headless-components-preview
react-headless-components-preview: Calendar
42.084 kB
13.907 kB
react-headless-components-preview
@fluentui/react-headless-components-preview/tag-picker
50.254 kB
16.375 kB
react-headless-components-preview
@fluentui/react-headless-components-preview/teaching-popover
33.766 kB
11.09 kB
🤖 This report was generated against c7b45497721c65bf274f790bfa5f4d87e56710bb

@github-actions

Copy link
Copy Markdown

Pull request demo site: URL

…daries

Forward root and InfoButton keys through the slot runtime so custom render functions cannot bypass the keyed boundary. Reset ownership for root-driven remounts and cover normalized keys, defaults, stale callbacks, and commit-time ownership.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3d006ca2-c036-45bf-bac0-93275c5dfe08
…tions

Add explicit outside controls and assert destination focus in InfoLabel Tab dismissal tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…cus dismissal

Defer shared focus-dismissal integration and preserve the existing blur behavior. Keep controlled/default/keyed ownership fixes, and exercise their accepted and rejected requests through trigger toggles without excluding tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3d006ca2-c036-45bf-bac0-93275c5dfe08
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d006ca2-c036-45bf-bac0-93275c5dfe08
@PaulGMardling Paul Mardling (PaulGMardling) changed the title fix(react-headless-components-preview): synchronize InfoLabel ownership fix(react-headless-components-preview): track controlled and keyed InfoLabel ownership Oct 20, 2026
…import

Use the repository's react-hooks alias so ownership lifecycle tests run with React 17's Testing Library as well as React 18 and 19.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3d006ca2-c036-45bf-bac0-93275c5dfe08
…rship lifetime

Replace the callback-driven open mirror with private mounted-instance reports. Reconcile ownership during layout for renderer-owned keys, renderer-mode changes, omitted buttons, and stale callbacks, while isolating nested buttons and preserving SSR bootstrap and consumer ownership.

Keep legacy blur behavior, public API signatures, and shared JSX/Popover implementations unchanged. Add before/after regression coverage and real-browser returned-key replacement checks.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3d006ca2-c036-45bf-bac0-93275c5dfe08
…s with WAI-ARIA

Use a div-based note with no menu announcement and retain the open trigger-to-note details relationship. Remove generated ownership and its private state/context machinery while preserving consumer ARIA overrides and actual InfoButton state.

Preserve explicit focus-trapping as a named native dialog with matching popup semantics. Cover controlled/default state, SSR, remounts, portals, keyboard behavior, names and consumer overrides across React versions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3d006ca2-c036-45bf-bac0-93275c5dfe08
@PaulGMardling Paul Mardling (PaulGMardling) changed the title fix(react-headless-components-preview): track controlled and keyed InfoLabel ownership fix(react-headless-components-preview): correct InfoLabel note semantics Oct 26, 2026

This branch has not been deployed

No deployments
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