Skip to content

fix(react-headless-components-preview): recover TeachingPopover focus when a navigation button is hidden - #36989

Open
Paul Mardling (PaulGMardling) wants to merge 7 commits into
microsoft:masterfrom
PaulGMardling:fix/39651-feature-tour-focus-recovery
Open

Paul Mardling (PaulGMardling) wants to merge 7 commits into
microsoft:masterfrom
PaulGMardling:fix/39651-feature-tour-focus-recovery

Conversation

@PaulGMardling

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

Copy link
Copy Markdown
Contributor

Previous Behavior

The downstream Fluent UI Modern Feature Tour in 1JS hides Previous on its first page. Navigating 2 → 1 can leave keyboard focus on the document body instead of an available tour control.

New Behavior

Recover focus to the opposite footer navigation button when the focused button becomes unavailable during a committed update. Ordinary navigation retains focus, and deliberate focus changes are respected.

This is internal to react-headless-components-preview: no new public props, no changes to styled TeachingPopover, and consumers still control visibility. Includes controlled-state, shadow-root, ref-cleanup, and hidden-ancestor regressions.

Verification (2026-10-26):

  • yarn nx run react-headless-components-preview:test --runInBand --skipNxCache — passed: 90 suites / 1,341 tests.
  • yarn nx run-many --targets=build,lint,type-check --projects=react-headless-components-preview --excludeTaskDependencies --parallel=1 — passed. Current CI, including React-version integration, bundle isolation and bundle size, is green.
  • Chrome 155: a minimal consumer bridge using the public headless hooks/renderers, a composed Button root and :empty { visibility: hidden } loses focus before the fix and recovers to Next with it. Normal 3 → 2 navigation retains Previous focus; Tab/Shift+Tab passes in light DOM and open/closed shadow roots. This is not an installed downstream-release test; Narrator/NVDA speech remains unverified.

Reproduction: start a three-page carousel on page 3, with consumer CSS hiding empty Previous content. Focus Previous and activate twice: 3 → 2 must retain Previous focus; 2 → 1 must focus Next when Previous hides. Shift+Tab must skip the hidden control.

The runnable regression is packages/react-components/react-headless-components-preview/library/src/components/TeachingPopover/TeachingPopoverCarouselFooter/TeachingPopoverCarouselFooter.test.tsx (run with the test command above; Node 22 and installed repository dependencies required). The Chrome before/after comparison substituted the original hook/renderer into the same dependency build, not a separate full build. A durable interactive browser walkthrough is still outstanding.

Screenshots omitted: UI-only images would not establish focus order or spoken output; keyboard and focus assertions are the relevant evidence. Accessibility reference: WCAG 2.4.3 Focus Order.

Related Issue(s)

Azure DevOps links require the appropriate Microsoft access. This PR addresses upstream focus recovery, not the entire downstream announcement issue.

Integration: the consumer can keep its public hook/renderer composition and CSS visibility policy without a focus adapter or new public API. The fix must be released and adopted downstream before installed-package verification; announcement/content and scrolling work remain separate.

Expose committed boundary state and add opt-in boundary hiding with explicit footer focus recovery. Preserve default behavior and cover navigation, controlled state, focus ownership, and ref forwarding.

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

Copy link
Copy Markdown

Pull request demo site: URL

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve consumer-controlled visibility and remove the boundary-hiding API and styled package changes. Recover after sibling refs reattach and clear stale focus ownership, with focused regression coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@PaulGMardling Paul Mardling (PaulGMardling) changed the title fix: recover headless TeachingPopover focus at carousel boundaries fix: recover headless TeachingPopover focus when a navigation button is hidden Oct 26, 2026
Use mount-safe focus callbacks and shadow-aware ownership checks. Replace the forbidden Tabster runtime with a private availability check that preserves programmatic focusability, and cover the reported regressions.

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

github-actions Bot commented Oct 26, 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
271.05 kB
80.835 kB
1.846 kB
651 B
react-headless-components-preview
@fluentui/react-headless-components-preview/teaching-popover
33.766 kB
11.09 kB
35.824 kB
11.849 kB
2.058 kB
759 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
🤖 This report was generated against 945d9def1e1187f297a7139791b1f9be396d5e32

Set the inert attribute through a ref so older React versions do not omit the fixture's boolean attribute.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Retain callback-ref cleanup on replacement and unmount without changing legacy null-detachment behavior. Respect explicit focus on the carousel shadow host and cover both open and closed roots.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Recognize content-visibility hidden ancestors and closed details while preserving the first visible summary. Cover hidden recovery destinations and preserve programmatic focus behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@PaulGMardling
Paul Mardling (PaulGMardling) marked this pull request as ready for review October 26, 2026 16:06
@PaulGMardling Paul Mardling (PaulGMardling) changed the title fix: recover headless TeachingPopover focus when a navigation button is hidden fix(react-headless-components-preview): recover TeachingPopover focus when a navigation button is hidden 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant