Skip to content

Accessibility: a title on every control, AA contrast, kept focus and reduced motion - #34

Merged
davd-gzl merged 10 commits into
mainfrom
a11y-sweep
Sep 30, 2026
Merged

davd-gzl merged 10 commits into
mainfrom
a11y-sweep

Conversation

@davd-gzl

Copy link
Copy Markdown
Collaborator

Based on #31, whose branch it builds on; merge that first.

248 controls had no title, although the repo's rule asks one of every interactive control. A unit test now parses every .tsx file and fails on a control with neither a title nor a spread that could carry one. 199 controls got a title taken from their visible label or aria-label; the other 49 sit in the map, places and search files another branch is rewriting, and wait in a marked block of the test until it lands.

Six colour pairs were below the 4.5:1 AA contrast, the worst a photo caption at 2.48 and a dark-mode chip at 2.19. They now reach at least 4.6, and the look stays the same except that the Filter chip loses a grey fill it never meant to have.

The axe check now runs on 29 screens and dialogs, each in light, dark and at phone width, one test per screen so a failure names it. The only violation left is the nested buttons in search results, which the same pending branch owns.

New story and ten other buttons that remove themselves when pressed dropped keyboard focus onto the page. Focus now moves into what opened and back to the opener when it closes. Page scrolls and generated content also honour reduced motion, and editing a trip whose form was closed scrolls to the form again.

The repo rule gives every interactive control a title, and nothing checked
it: 248 controls had none. The test parses every component with the
TypeScript compiler and lists each button, link, form field, summary and
role-carrying control without a title attribute or a spread that could
carry one. The map, visits and search components are held out while their
rewrite lands.
A mouse user hovering a button, link or field got no tooltip naming it on
199 controls, against the repo rule. Each now carries a title in the words
of its visible label, its aria-label or its field label, from the existing
strings in every language. MoreButton takes its label as a string so it
can reuse it as the title.
…idth

The gate covered five screens in the light scheme at desktop width, so
contrast failures on the place card, the Countries list, the photo viewer,
About, the Places chips in dark and the phone Stats numbers went unseen.
Each screen and dialog is now its own test, from a restored backup with
trips, stories and photos, in light, dark and at 375 px. The search
results stay out while their nested button is reworked.
Six pairs failed axe: the visited green on the beige card and in the
Countries badges, the place card's green in dark, the photo caption on the
dark viewer, the faded About version line, and the Filter chip in dark,
which drew grey system button colour behind muted text. The visited green
darkens one step, the place card reads the theme's visited token, the
caption takes the viewer's own light grey, the version line drops its fade
and the chip draws no background.
New story hides itself while the composer is open, so clicking it dropped
keyboard focus on the page body, and closing the composer did the same.
Opening now focuses the composer's Place field, and Cancel, Escape or Save
give focus back to the control that opened it, or to New story.
Ten controls vanished when pressed and dropped keyboard focus on the page
body: New trip, the boarding-pass open and Close buttons, the world
poster Close, Disconnect, the sync guard and the offline-map reset
confirm, the late-night day choice, the phone recommendation in the
intro, and Publish when closed. A small hook now hands focus to the
control that takes the removed one's place, only when focus was lost, and
Publish returns focus to its opener as About already does.
…ntent

With reduced motion asked for, opening the journal composer or editing a
trip still scrolled the page smoothly, and the global rule that stops
transitions matched elements but not their ::before and ::after, so the
Settings disclosure arrow still turned. Both scrolls now jump under reduced
motion, and the rule covers generated content. Editing a trip while its
form was closed scrolled nowhere, since the form was not yet drawn; the
scroll now waits for it. Map camera moves already jump: MapLibre skips
non-essential animation under reduced motion and the app passes a zero
duration.
- JournalScreen: main moved writing onto the StoryComposer page and dropped
  the inline form and the late-night day choice, so main's side is kept
  there. The titles this branch put on the reader's controls stay, now
  labelled with entryLabel, since a postcard's place is optional.
- New story focus: the fix moves to the page model. Write a postcard hands
  focus back to itself when the composer it opened closes, and an edit
  opens on the composer's date field, since the Edit button that opened it
  is gone. journalComposerFocus.spec.tsx drives the page switch App makes.
- TripComposer: main's chain-based removeStopAt with this branch's title on
  the remove button; main's per-stop dates replace the year and month
  fields this branch had titled.
- a11y.spec.ts: the per-screen matrix in light, dark and at 375px stays;
  main's postcard composer test becomes its postcard composer screen with
  details open, and the matrix gains the station browse and asserts the
  trip composer's per-stop dates.
- Reduced motion and focus handoff: the journal cases go with the inline
  composer and the day choice they covered.
The title guard listed 26 controls main brought in without one: every field
and button of the postcard composer, the Journal's tag chips, the per-stop
date, legacy date chip and linked postcards of the trip composer, the route
map's kind filter and the station dataset picker in Settings. Each takes the
label or aria-label it already shows, from existing en, fr and ko keys.
@davd-gzl
davd-gzl changed the base branch from audit-fixes to main September 30, 2026 17:24
@davd-gzl
davd-gzl merged commit c072a6a into main Sep 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant