Reusable accessible patterns
Every pattern below uses the actual shared components from src/components/: tab through it, trigger errors, and open the modal.
Field error & form success
Required field with an inline, programmatically-associated error (role="alert", aria-invalid, aria-describedby) and a success confirmation (role="status").
We use this only to send your requested proposal.
Disabled & loading actions
A loading button exposes aria-busy and an SR-only status; a disabled action uses disabled + aria-disabled with a visible reason.
Empty state
No saved locations yet
Browse the Location Library and save a location to see it here. Empty states explain the next step, never a dead end.
Keyboard focus
Tab through these controls — each shows a 2px gold focus-visible ring (never removed). The skip link at the top of every page jumps straight to main content.
Screen-reader label
Icon-only controls carry an aria-label; the glyph is aria-hidden.
Modal focus trap
Opening the dialog moves focus inside, traps Tab within it, closes on Escape or backdrop, and returns focus to the trigger.
