Repository navigation
fix(Dialog): capture the opener before descendant autofocus effects - #6607
ManoharPaturi wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR Analysis Report📚 Storybook Preview🧪 Sandbox PreviewView Sandbox for this PR No new or modified components detected. Bundle Size Summary
Accessibility AuditStatus: No accessibility violations detected. Visual Regression25 of 420 shot(s) changed. View the report A change here is a question, not a failure: check whether the after is the
and 5 more. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
|
AI review status for this pull request.
|
There was a problem hiding this comment.
Thanks — the focus fix itself looks right and matches the Dialog contract: capturing the opener in a layout effect means a DialogHeader that mounts in the open commit can no longer replace the return target, and suppressing header autofocus while the dialog is closed stops focus landing on an invisible title. The new regressions cover both shapes, and the Dialog and dependent suites pass.
One change is needed before this lands:
packages/core/src/Dialog/__tests__/Dialog.a11y.known-failures.tsstill recordsmodal-dialog.focus.restoredfor theconditional-content-focus-restorationstate as a current failure ("closing the modal dialog did not return focus to its still-available invoker"). This PR makes that outcome pass, and the Chromium accessibility contract requires every known-failure record to match exactly one executed result — an unmatched record failsDialog.a11y.chromium.spec.tswhen it runs at release-check (it does not run in PR CI, which is why checks are green). Please delete just that record, keeping theenters-after-modalrecord, whose focus-entry ordering this PR does not change and which remains accurate. Running the Dialog Chromium accessibility spec after the removal, where a browser is available, would confirm it.
No other blocking issues were found; the pre-existing focus-entry ordering issue stays recorded and is out of scope here.
[Automated review]









Fixes #5637
Summary
A controlled Dialog whose content mounts in the open commit restored focus to
<body>on close. Two defects, both fixed:document.activeElementin its passive effect, but React runs child passive effects before the parent's — so a freshly mounted DialogHeader focused its own title first, and the Dialog captured its own heading. When closing unmounts that content, focus restoration targeted a detached node and the user's focus stranded on<body>. The capture now runs in auseLayoutEffecton the open edge: all layout effects run before any passive effect, so the capture always sees the element the user was on before the dialog's descendants moved focus.shouldAutoFocuscheck only excluded inline mode, and the standard path renders children (hidden) while closed, so a header mounted underisOpen={false}stole focus onto an invisible element.DialogContextnow carriesisOpen, and the header suppresses autofocus while closed — its effect re-runs when the dialog opens, so the title still becomes the screen reader anchor on open, exactly as before for content that mounts in the open commit.Tests
document.activeElementis the opener. Failed on main (focus landed on<body>), passes here.DialogHeadermounted underisOpen={false}leaves focus on<body>. Failed on main (title stolen focus), passes here.Verification
tsc --noEmitclean (core); eslint 0 problems on touched files; prettier clean;check:changesetsclean. Changeset included.