Skip to content

fix(ui): restore shadow dialog focus after rapid reopen (YPE-5889) - #413

Closed
abharms wants to merge 2 commits into
youversion:journey-to-the-shadow-domfrom
abharms:ype-5889-shadow-overlay-runtime
Closed

abharms wants to merge 2 commits into
youversion:journey-to-the-shadow-domfrom
abharms:ype-5889-shadow-overlay-runtime

Conversation

@abharms

@abharms abharms commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Targets journey-to-the-shadow-dom, which contains the existing Shadow DOM overlay seam.

  • preserve the original opener when a controlled shadow dialog closes and reopens during retained exit presence
  • restore final focus only when the target remains connected in the owning shadow root
  • discard stale focus targets when a consumer prevents close autofocus
  • add direct Chromium evidence for rapid reopen, nested teardown, cross-root targets, and disconnected targets
  • reconcile the Shadow DOM ADR and rollout plan, and add a UI patch changeset

Requirement evidence

Jira acceptance area Evidence
Rapid close/reopen regression The Chromium story closes the dialog, reopens it during the retained 300 ms exit, dismisses it again, and asserts final focus returns to the original Run control.
Valid final restoration useShadowDialogFocus retains the first captured opener through the interrupted exit; ShadowRootHost restores it after modal release.
Invalid targets ignored Restoration now requires a connected target whose root is the owning shadow root. Chromium evidence covers both moving the opener to another shadow root and removing it from the document.
Nested overlays remain correct The existing popover-to-dialog production-seam story now asserts intermediate focus inside the popover and final focus on the original outside control. The inverse dialog-to-popover story remains green.
Consumer-prevented autofocus A focused unit regression proves that preventing one close autofocus clears the stored opener so a later dialog session captures and restores its own opener.
Documentation and release impact ADR 0007 and the rollout plan now record supported final restoration and retain peer concurrency/cross-browser limits. A UI patch changeset is included.

Review scope

Required outcomes:

  • restore the original valid opener after rapid close/reopen during retained exit presence
  • ignore disconnected and cross-root restoration targets
  • preserve nested popover/dialog and light-DOM behavior
  • cover the behavior with focused unit and Chromium evidence

Permitted support work:

  • the smallest focus-lifecycle changes in the existing dialog and shadow-host seams
  • focused Storybook fixtures and unit regressions
  • directly corresponding ADR/rollout documentation and a patch changeset

Non-goals:

  • an overlay manager, ownership stack, or peer-concurrency runtime
  • public API, dependency, or broad Radix behavior changes
  • unrelated cleanup or automatic component rollout
  • exhaustive cross-browser or assistive-technology validation

Review only against YPE-5889 and this stated scope. Treat correctness defects, regressions, explicit repository-rule violations, and unmet required outcomes as blocking. Treat broader hardening, optional refactors, and out-of-scope improvements as follow-up work.

Verification

  • focused Chromium Shadow DOM overlay story file — 9/9 passed
  • focused dialog unit tests — 3/3 passed
  • pnpm --filter @youversion/platform-react-ui typecheck — passed
  • pnpm lint — passed
  • pnpm turbo build --force --filter=@youversion/platform-react-ui — passed
  • pnpm test — passed on clean rerun; all six workspace tasks green, UI 545/545
  • pnpm exec prettier --check ... and git diff --check — passed
  • final independent Standards, Spec, and Compatibility audits at a7cfe28 — no required or advisory findings

The first concurrent full-suite run hit the existing five-second timeout in bible-reader-controlled.test.tsx. The unchanged timed-out test passed 33/33 in isolation, and the complete suite then passed on rerun.

Compatibility and limitations

  • Light-DOM/document-portaled dialogs continue through the unchanged Radix-owned focus path.
  • Public exports, props, types, and dependencies are unchanged.
  • Peer overlay concurrency remains outside this ticket and is still documented as rollout work.
  • Chromium provides the direct browser evidence; cross-browser and assistive-technology validation remain follow-up gates.

Jira

Greptile Summary

This PR fixes final focus restoration for Shadow DOM dialogs that close and reopen during retained exit presence.

  • Preserves the original opener across an interrupted dialog exit.
  • Restores focus only to a connected target in the owning shadow root.
  • Clears stale targets when consumers prevent close autofocus.
  • Adds focused unit and Chromium coverage for rapid reopen, nested overlays, cross-root targets, and disconnected targets.
  • Updates the Shadow DOM ADR, rollout plan, and UI package changeset.

Confidence Score: 5/5

The PR appears safe to merge with the required focus lifecycle, invalid-target handling, regression coverage, documentation, and release metadata aligned.

The changed capture and restoration paths preserve the original valid opener through rapid reopen, discard prevented or invalid targets, and are covered at both unit and Chromium integration levels without an established regression.

Important Files Changed

Filename Overview
packages/ui/src/components/ui/use-shadow-dialog-focus.ts Preserves an existing restore target through rapid reopen and clears it when consumer close autofocus is prevented.
packages/ui/src/lib/shadow-root-host.tsx Restricts immediate and deferred restoration to connected elements belonging to the host’s current shadow root.
packages/ui/src/components/shadow-overlay-production-seam.shadow-isolation.stories.tsx Adds Chromium coverage for rapid reopen, nested final restoration, and invalid opener targets.
packages/ui/src/components/ui/dialog.test.tsx Adds a focused regression proving a prevented close-autofocus session does not leak its opener into the next session.
docs/adr/0007-prototype-shadow-dom-style-isolation.md Updates the architectural record to describe supported final focus restoration and retained peer-concurrency limitations.
docs/shadow-dom-isolation-plan.md Reconciles rollout status and evidence with the newly supported restoration behavior.
.changeset/quiet-dialogs-return.md Records the user-facing focus-restoration correction as a UI package patch.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Dialog opens] --> B[Capture focused opener]
  B --> C[Dialog begins closing]
  C --> D{Reopened during retained exit?}
  D -->|Yes| E[Preserve original opener]
  E --> C
  D -->|No| F[Wait for final modal release]
  F --> G{Target connected and in owning shadow root?}
  G -->|Yes| H[Restore focus]
  G -->|No| I[Discard target]
  C --> J{Consumer prevented close autofocus?}
  J -->|Yes| K[Clear stored opener]
Loading

Reviews (1): Last reviewed commit: "fix(ui): reset prevented shadow focus re..." | Re-trigger Greptile

Context used:

@changeset-bot

changeset-bot Bot commented Sep 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a7cfe28

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@youversion/platform-react-ui Patch
vite-react Patch
@youversion/platform-core Patch
@youversion/platform-react-hooks Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-16T21:25:11.220750Z a7cfe28 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@abharms

abharms commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #414, which uses the identical reviewed commit from an upstream branch so CI can access the repository's required test environment.

@abharms abharms closed this Sep 16, 2026
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