From 4f79a816e49af44b8a5ee04b45fa741e020c7ce8 Mon Sep 17 00:00:00 2001 From: Claude Fable 5 Date: Thu, 16 Jul 2026 12:16:20 +0200 Subject: [PATCH] Toast stack: drop role=status from the global live region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The always-mounted toast container carried role="status", so every page-scoped getByRole('status') locator suddenly resolved to two elements — legal.spec failed CI with a strict-mode violation. The region keeps aria-live="polite" (announcements work the same); the status role stays with the per-page elements that had it before. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb2VzvcoBPHkjh8bZ6PzQn --- apps/web/src/components/Toast.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/Toast.tsx b/apps/web/src/components/Toast.tsx index 022447d..64d5983 100644 --- a/apps/web/src/components/Toast.tsx +++ b/apps/web/src/components/Toast.tsx @@ -3,7 +3,7 @@ import { createContext, useCallback, useContext, useRef, useState } from 'react' /** * App-wide toast notifications (issue #130). One provider near the root owns * the stack; `useToast()` hands out a fire-and-forget `showToast`. Toasts are - * announced politely (`role="status"` on the stack container), stack bottom + * announced politely (`aria-live` on the stack container), stack bottom * center above the footer, and dismiss themselves — clicking one dismisses * it early. The plugin host's `ui.toast` capability feeds the same stack. */ @@ -49,8 +49,11 @@ export function ToastProvider({ children }: { children: React.ReactNode }): Reac {children} {/* The live region exists permanently, so screen readers pick up toasts added to it; individual toasts must not carry their own - role="status" (a region appearing WITH its content isn't read). */} -
+ role="status" (a region appearing WITH its content isn't read). + Deliberately aria-live WITHOUT role="status": the region is + global and always mounted, and a second status role broke every + page-scoped getByRole('status') locator (legal.spec, CI). */} +
{toasts.map((toast) => (