Skip to content

a11y(2.4.3): keep toast live region announcing during a focus trap [DT-4252]#3654

Merged
ardiewen merged 2 commits into
mainfrom
worktree-DT-4252-toast-live-region
Jul 10, 2026
Merged

a11y(2.4.3): keep toast live region announcing during a focus trap [DT-4252]#3654
ardiewen merged 2 commits into
mainfrom
worktree-DT-4252-toast-live-region

Conversation

@ardiewen

@ardiewen ardiewen commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #3598, from Laura's review. The inert-based trap inerts everything outside it up to <body>; the toast aria-live region lived inside the main app container, so toasts fired while a drawer/maximizable was open were not announced to screen readers (still shown visually — an AT-only gap).

Fix: hoist the live region to <body> from within Toaster (data-inert-skip), and have inertBackground skip live-region roots — matched on the element itself, so a container merely holding a live region (the app shell) is still inerted and containment is preserved.

Stacked on wcag/2.4.3-focus-trap-inert (#3598); retarget to main once it merges. cloud-ui picks this up on the next tarball repack — verify both its toaster mounts then (see DT-4252).

Testing

  • 3 new unit tests in focus-trap.test.ts: skips data-inert-skip / aria-live roots; still inerts a container with a nested live region.
  • pnpm check clean, focus-trap suite green.
  • NVDA/VoiceOver: toast announced with a drawer/maximized surface open.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Jul 10, 2026 6:53pm

Request Review

@github-actions github-actions Bot added a11y Accessibility audit PR a11y:no-fix-doc No A11y-Audit-Ref line; audit team triage labels Jul 10, 2026
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Accessibility triage

No A11y-Audit-Ref: lines found in the PR body. If this PR closes an audit fix doc, add an A11y-Audit-Ref: <slug> line (one per fix doc). If this is a net-new accessibility finding not yet covered by the audit, coordinate with the audit team via #team-feux so they can add a manifest entry.


See DT-4048 for the triage system design.

@ardiewen ardiewen marked this pull request as ready for review July 10, 2026 15:42
@ardiewen ardiewen requested a review from a team as a code owner July 10, 2026 15:42
@ardiewen ardiewen requested a review from laurakwhit July 10, 2026 15:42
Comment thread src/lib/utilities/focus-trap.test.ts Outdated
Base automatically changed from wcag/2.4.3-focus-trap-inert to main July 10, 2026 18:48
ardiewen and others added 2 commits July 10, 2026 14:51
…T-4252]

The inert-based focus trap (#3598) inerts everything outside the trap up
to <body>. The Toaster's aria-live region rendered inside the main app
container, so it was inerted while a drawer/maximizable was open and toasts
went unannounced to screen readers (still shown visually — an AT-only gap).

Hoist the live region to <body> from within the Toaster and mark it
data-inert-skip; inertBackground now skips live-region roots (matched on the
element itself, so a container merely holding one is still inerted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The data-inert-skip test also set aria-live, so it passed on the aria-live
branch alone. Drop aria-live here so it exercises data-inert-skip only;
aria-live has its own test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
</div>

<div class={toast({ position: $position })}>
{#each $toasts as { message, variant, id, link } (id)}

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.

  • ⚠️ Type 'ToastVariant | undefined' is not assignable to type 'ToastVariant'.
  • ⚠️ Type 'string | undefined' is not assignable to type 'string'.

@temporal-cicd

temporal-cicd Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

📊 Strict Mode: 2 errors in 1 file (0.2% of 895 total)

src/lib/holocene/toaster.svelte (2)
  • L57:40: Type 'ToastVariant | undefined' is not assignable to type 'ToastVariant'.
  • L57:50: Type 'string | undefined' is not assignable to type 'string'.

Generated by 🚫 dangerJS against 05f1386

@ardiewen ardiewen merged commit cc491a2 into main Jul 10, 2026
19 checks passed
@ardiewen ardiewen deleted the worktree-DT-4252-toast-live-region branch July 10, 2026 20:24
@ardiewen

Copy link
Copy Markdown
Contributor Author

Downstream repack: temporalio/cloud-ui#2929 (release-ui) — this change is the tip commit (cc491a29) of that pack.

What needs to happen on the cloud-ui side (on #2929):

  1. Verify announcements at both toaster mounts — with a drawer/maximized surface open, confirm a toast is announced (NVDA/VoiceOver):
    • src/routes/(app)/+layout.svelte
    • src/routes/(app)/get-started/+layout@.svelte
  2. Check Playwright selectors — the toast LiveRegion is now portaled to <body>, so integration tests that scope to a page container when querying getByRole('status'|'alert'|'log') or the toast-live-region-* testids may need updating (same pattern as a11y(4.1.3): Toaster role="log" → per-toast role="status"/"alert" for correct AT announcement semantics #3560 → cloud-ui#2832). Expect a fix commit on the repack PR if those break.
  3. Out of scope: native <dialog> modals still inert the document (incl. the hoisted live region) — a separate, pre-existing gap tracked in DT-4252, not addressed by this repack.

rossedfort added a commit that referenced this pull request Jul 13, 2026
Auto-generated version bump from 2.52.0 to 2.52.1

Bump type: patch

Changes included:
- [`3be0df00`](3be0df0) fix(schedules): default absent second/minute/hour to 0 when editing (#3653)
- [`508b65b7`](508b65b) fix(schedules): default emptied second/minute/hour to 0 on submit (#3655)
- [`1f0e149c`](1f0e149) fix(workers): reject $LATEST qualifier in Lambda ARN validation (#3657)
- [`b42b0776`](b42b077) a11y(2.4.3): inert-based focus containment + restore; drop trap from native dialogs (#3598)
- [`cc491a29`](cc491a2) a11y(2.4.3): keep toast live region announcing during a focus trap [DT-4252] (#3654)
- [`ddc7f8e2`](ddc7f8e) a11y(2.4.11): add scroll-padding so sticky overlays don't obscure focused elements (#3532)
- [`b7e3a472`](b7e3a47) FilterBar icon update (#3660)
- [`09318ec6`](09318ec) Add danger PR comment for api version bump (#3662)
- [`273cc4be`](273cc4b) a11y(4.1.2): add label prop to Button primitive and enforce accessible names (#3556)
- [`4507115f`](4507115) Use an editable combobox for the Cloud Run region field (DT-4232) (#3636)
- [`694a7471`](694a747) a11y(1.4.13): migrate saved-query nav tooltips to Tooltip primitive (#3607)
- [`8b384a40`](8b384a4) a11y(4.1.2): fix nested interactive elements in Copyable component (#3558)
- [`1bfd2750`](1bfd275) fix describe SANO API requests to include runId parameter (#3661)
- [`ba18b43e`](ba18b43) a11y(4.1.2): require label on CodeBlock primitive; add aria-readonly for read-only mode (#3557)
- [`6e2290f1`](6e2290f) feat(deployments): make compute provider picker configurable (#3659)
- [`4470b76a`](4470b76) fix(workers): persist WDV compute-config edits via update mask; revert $LATEST validation (#3658)
- [`17fd591b`](17fd591) fix(nexus-operations): make start standalone nexus operation timeouts optional (#3656)

Co-authored-by: rossedfort <11775628+rossedfort@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a11y:no-fix-doc No A11y-Audit-Ref line; audit team triage a11y Accessibility audit PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants