Skip to content

fix(a11y): modal accessibility — aria-modal + focus trap; consolidate on ui/Modal (destructive modals first) #251

Description

@ajianaz

Problem

Modals in the app have inconsistent accessibility. Only SettingsModal and DetailPanel are fully correct.

Modal role=dialog aria-modal focus management
SettingsModal.svelte:86 ✅ + aria-label ❌ no focus move/trap
DetailPanel.svelte
LifecycleView.svelte:295 (Run Cycle)
ConsolidatePanel.svelte (Confirm Remove)
MemoryEditor.svelte:169 (modal-overlay)
ui/Modal.svelte (shared primitive) ❌ (Escape ✅)

Key gaps: keyboard Tab can escape behind the overlay on all modals; destructive-action modals (Run Cycle, Remove duplicates) are the least accessible.

There is a shared ui/Modal.svelte (Escape handling, backdrop, scale transition) but most modals don't use it — every component rolls its own.

Fix

  1. Harden ui/Modal.svelte as the single modal primitive: add role="dialog", aria-modal="true", aria-label, focus-on-open (focus first focusable / Cancel button), basic focus trap (Tab/Shift+Tab cycle), restore focus on close
  2. Migrate modals to it — priority order: ConsolidatePanel (destructive)LifecycleView (destructive) → MemoryEditor → keep SettingsModal/DetailPanel markup but add focus handling

Source

Full-app UI audit (a11y; destructive flows get priority).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions