fix(a11y): name the headless modals too — Seen by, source, file viewers (#185)
CI / Build & Quality Checks (push) Successful in 1m41s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 11s
CI / Trigger Desktop Build (push) Successful in 9s
CI / Playwright smoke (e2e) (push) Successful in 13m14s

Follow-up to ce8ed89f for the modals that have no visible heading to
point at: the three "Seen by" reader lists (read-receipt pill, "is
following", message menu), View source, the text/PDF file viewers, the
room-card join error and the user-profile modal get role="dialog",
aria-modal and an aria-label; their traps move focus in (fallbackFocus
on the dialog) where the trap is local.

Verified: the receipt pill opens a "Seen by" dialog with focus on
Close; Escape closes it and focus returns to the pill.

The remaining unnamed Modal/Dialog uses are startup/loading and error
screens (config, feature check, spec versions, client root, password
reset) and wrappers around components that carry their own role (image
viewer).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
Lotus CI
2026-09-24 13:12:13 -04:00
co-authored by Claude Opus 5.5
parent ce8ed89fdc
commit 7f2e93d389
6 changed files with 73 additions and 13 deletions
@@ -105,13 +105,18 @@ export function ReadTextFile({ body, mimeType, url, encInfo, renderViewer }: Rea
<OverlayCenter>
<FocusTrap
focusTrapOptions={{
initialFocus: false,
fallbackFocus: '#file-viewer-2-dialog',
onDeactivate: () => setTextViewer(false),
clickOutsideDeactivates: true,
escapeDeactivates: stopPropagation,
}}
>
<Modal
id="file-viewer-2-dialog"
role="dialog"
aria-modal="true"
aria-label={`File: ${body}`}
tabIndex={-1}
className={ModalWide}
size="500"
onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
@@ -194,13 +199,18 @@ export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer }: Read
<OverlayCenter>
<FocusTrap
focusTrapOptions={{
initialFocus: false,
fallbackFocus: '#file-viewer-1-dialog',
onDeactivate: () => setPdfViewer(false),
clickOutsideDeactivates: true,
escapeDeactivates: stopPropagation,
}}
>
<Modal
id="file-viewer-1-dialog"
role="dialog"
aria-modal="true"
aria-label={`File: ${body}`}
tabIndex={-1}
className={ModalWide}
size="500"
onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}