Repository navigation
[all components] Contain modal focus across nested popup roots - #6197
Closed
FelixTJDietrich wants to merge 6 commits into
Closed
FelixTJDietrich wants to merge 6 commits into
FelixTJDietrich wants to merge 6 commits into
Conversation
FelixTJDietrich
requested review from
atomiks,
colmtuite,
flaviendelangle,
jjenzz and
michaldudak
as code owners
November 6, 2026 16:51
commit: |
Bundle size
PerformanceNo regressions in 36 benchmarks · ran 3m 52s · details Check out the code infra dashboard for more information about this PR. |
✅ Deploy Preview for base-ui ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
Use the renderer user helper so dismissal receives a new press and release rather than a click-only event racing the scrub-release guard. Preserve the dismissal assertions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A modal popup can hide background controls from accessibility APIs while leaving them focusable. Apply native
inertat the owning popup layer so background controls stay excluded and nested popups remain usable across portals.Addresses #4678; related to #4714. Public props remain unchanged.
Implementation
The change belongs in Base UI's interaction runtime. Consumers need no second focus trap, wrapper observer or repository-only dependency patch.
Regression tests
The shared modal suite covers ownership, portals, shadow roots, initial/return focus, dynamic controls, announcement accessibility and cleanup. It includes positive controls proving inside activation and post-unmount outside activation still work.
The animation helper tests cover stalled rendering frames, already-finished animations and real newly introduced CSS exit animations/transitions. Existing batching, cancellation and StrictMode tests remain intact. Existing Menu and Popover trigger-switch regressions protect motion and cancellation.
The two native Toast expiry tests now control only timers and
Date; real pointer input, window focus and animation frames remain real. They assert pause and subsequent expiry after interaction ends, instead of racing a 300 ms toast against browser automation. The existing scrub-dismissal conformance input uses a fresh rendereruser.clickpress/release rather than a click-only synthetic event. Assertions and timeouts were not weakened, and no new skips or retries were added.Deliberately breaking pause, resume, outside activation exclusion, closed-shadow admission, frame-independent completion and finished-animation handling fails the corresponding regressions. Additional existing focus/validation counterfactuals are retained in local evidence.
Validation
The earlier full React 18 JSDOM repair passed locally; the complete React 18 matrix must be confirmed on the final pushed source by upstream CI. The final packed downstream campaign replaces neither normal declared-dependency CI nor durable dependency delivery: it deliberately installs a local candidate archive and verifies matching bytes and a single shared Base UI runtime.
Full upstream CI is rerunning on the final commits. A maintainer must apply a label for the repository's
test-label-appliedcheck. This PR does not publish an npm release or adopt a preview dependency in downstream production manifests. Manual screen-reader speech remains unverified.