Skip to content

fix: restore headless TeachingPopover close focus - #36843

Open
Paul Mardling (PaulGMardling) wants to merge 8 commits into
microsoft:masterfrom
PaulGMardling:fix/39652-teaching-popover-close-focus
Open

Paul Mardling (PaulGMardling) wants to merge 8 commits into
microsoft:masterfrom
PaulGMardling:fix/39652-teaching-popover-close-focus

Conversation

@PaulGMardling

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

Copy link
Copy Markdown
Contributor

Previous Behavior

Headless Popover unmounted its surface before native close could restore focus, and the non-modal path never called hidePopover(). This could leave focus on the document body when a TeachingPopover tour closed.

New Behavior

Shared headless Popover keeps the surface connected until hidePopover() or close() completes, then unmounts it. TeachingPopover inherits the fix without a document-wide focus listener. A guarded trigger fallback handles surface-owned focus when native restoration has no viable target, including initially-open tours and shadow roots; native restoration and intentional outside focus take precedence.

Includes regression coverage, documentation, updated hook-state API reports, and a patch change file. Styled v9 components and carousel navigation are unchanged.

Validation

Checked locally on 2026-10-12: 62 unit tests and 66 Cypress tests passed (Electron, retries disabled; three existing skipped cases). Browser coverage checks native close before unmounting, Got it/Escape dismissal, modal/non-modal tours, shadow roots, reopening, and outside focus preservation. Build, type-check, lint, and API generation passed.

Related Issue(s)

  • Partially addresses ADO 39652. Modern must consume the released fix; its Previous-to-Next boundary focus change is separate. Do not close the bug: TCS/E+D Accessibility testers must verify the complete fix first.

Restore trigger focus after a focused TeachingPopover surface is removed on close, without overriding native restoration or deliberate outside focus.

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

github-actions Bot commented Oct 7, 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
244.71 kB
69.082 kB
245.492 kB
69.316 kB
782 B
234 B
react-headless-components-preview
@fluentui/react-headless-components-preview/teaching-popover
36.155 kB
12.018 kB
36.933 kB
12.256 kB
778 B
238 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-headless-components-preview
@fluentui/react-headless-components-preview/tag-picker
54.101 kB
17.741 kB
🤖 This report was generated against 389e06cc77c7f3621bf2af7dea251fc12fe68a2f

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

Pull request demo site: URL

Track focus ownership using the surface root while preserving native restoration and intentional outside focus.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@PaulGMardling
Paul Mardling (PaulGMardling) marked this pull request as ready for review October 9, 2026 09:20
@PaulGMardling
Paul Mardling (PaulGMardling) requested a review from a team as a code owner October 9, 2026 09:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The focused behavior change is guarded against unwanted focus movement and has comprehensive unit and browser coverage.

0 open findings

What changed in this PR

Restores trigger focus when an initially open headless TeachingPopover closes after losing surface-owned focus.

Changes:

  • Tracks surface focus across controlled close transitions and shadow roots.
  • Adds unit and Cypress coverage for restoration and intentional focus movement.
  • Updates documentation and adds a patch change file.
File Description
TeachingPopoverDescription.md Documents close-focus behavior.
useTeachingPopover.ts Implements guarded trigger-focus restoration.
TeachingPopover.test.tsx Adds unit coverage for focus ownership and shadow roots.
TeachingPopover.cy.tsx Adds browser coverage for controlled tours and dismissal.
@fluentui-react-headless-components-preview-*.json Records the patch release.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Move close focus handling into shared Popover and remove the TeachingPopover-specific document listener. Preserve native restoration and intentional outside focus, with a guarded fallback for orphaned surface focus.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0d39e88a-f6af-41d5-a788-7aa0152d5210

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Nested open shadow roots can cause surface-owned focus to be misclassified and prevent trigger restoration.

1 open finding

🧠 Review effort: Balanced

Comment on lines +25 to +32
let activeElement =
ShadowRootConstructor && root instanceof ShadowRootConstructor
? root.activeElement ?? surface.ownerDocument.activeElement
: surface.ownerDocument.activeElement;
while (activeElement?.shadowRoot?.activeElement) {
activeElement = activeElement.shadowRoot.activeElement;
}
return activeElement;
Keep active element lookup relative to the surface root so containment checks recognize focused shadow hosts. Add unit and browser regressions for nested shadow focus restoration.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0d39e88a-f6af-41d5-a788-7aa0152d5210

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.

4 participants