Skip to content

fix(tour): the guided tour says each step once and never drops focus (v0.18.2) - #323

Merged
MerciHanrim merged 1 commit into
mainfrom
fix/tour-announcement
Oct 6, 2026
Merged

MerciHanrim merged 1 commit into
mainfrom
fix/tour-announcement

Conversation

@MerciHanrim

Copy link
Copy Markdown
Owner

Part of #308. Version 0.18.2: the guided tour says each step once, and focus is never lost.

What a person notices

  • Step 1 is read as the tour opens, by the dialog's name (1 / 6 and the step title) and its description (the step text). Focus starts on Next.
  • Every later step is read once, as N / 6. title. text, when Next or Back reaches it. Focus stays on Next or Back.
  • Back to step 1 moves focus to Next before Back is disabled, instead of dropping it.
  • Every way out (Done, Escape, the close button), on a first run or a replay, puts focus on the Help button: on the overflow button when the toolbar has folded Help into it, on More on a phone.
  • The welcome card's question is read as its description, with its title. Its buttons, their order and the first focus (Skip) are unchanged.
  • The phone tour has the same behaviour and the same layout.

Before this change (measured on v0.18.1)

  • From step 2 on, only 2 / 6 was read: the title and text changed in place and the position was the only live text.
  • Focus entered the tour on the close button.
  • Back down to step 1 disabled the focused Back button, and focus fell to the page itself inside the dialog.
  • A first-run tour ended by Done left focus on the page itself; a replay returned to Help or More.
  • Neither dialog had a description.

How

  • src/components/GuidedTour.tsx: the popover is labelled by its position and title (aria-labelledby) and described by its body (aria-describedby); focus enters on Next (useDialogFocus's initialFocus).
  • One hidden live region inside the popover (aria-live="polite", aria-atomic="true") is written by the Next or Back press itself, never by a render: it starts empty, so step 1 is not said twice, and a language switch mid-tour writes nothing. The visible N / 6 is no longer live.
  • The sentence is its own key, tour.nav.announce, in all 18 languages, with each language's own separators (。 in Japanese and Chinese, a space in Thai, the full stop elsewhere), not English punctuation joined in code.
  • Back to step 1 focuses Next first; Back stays disabled.
  • The exit target, in this order: the Help button, the overflow button (when Help is folded into it), More. A target that is gone, hidden, inert or disabled is skipped; visibility counts, because at 1280 px the overflow button is in the page with visibility: hidden (measured: focusing it left focus on the page). Only when none is usable, the top bar's first usable menu button outside the palette.

Tests

  • New e2e/tour-announcement.spec.ts (19 tests). From before the app boots it records every text the tour's live regions come to hold and every focus loss to the page itself.
  • The Welcome card: its name, and its question through aria-describedby, in Playwright's computation and in Chromium's own accessibility tree.
  • Step 1: the dialog named 1 / 6 plus its title and described by its body, also in Chromium's tree; focus on Next; nothing written to the live region.
  • Steps 2 to 6: each written to the live region exactly once; that region is the only live region in the tour; the title and the visible position are not live.
  • Back to step 1: focus on Next, never on the page itself. A language switch mid-tour announces nothing, and the next step is said once in the new language.
  • Done, Escape and the close button, first run and replay, at 1280 px and 390 px (Help, More), and Escape at 760 px (the overflow button). With Help hidden at 1280 px, a menu button of the top bar outside the palette.
  • Negative control: with the two focus fixes reverted, 9 of the 19 fail (Back to step 1, every first-run exit at all three widths, the fallback).

Release, strings and docs

  • Declared user-facing: 0.18.2 and release:0.18.2, three lines dated 2026-10-06, and the step sentence, in 18 languages. The 16 languages other than English and Korean have not been reviewed by a native speaker.
  • The English lines do not say "screen": the pt-PT audit forbids the word, since the product has no screen concept, so no line names a screen reader.
  • The per-language copy tests move their pinned counts by the four keys, and declare the step sentence where it reads the same as English and Escape where each guard asks. No bound is widened: the pt-PT audit's differing keys move from 269 to 270, and those outside the password keys from 241 to 242, under the unchanged quarter of the 970 non-password keys (242.5).
  • The ICU argument total moves from 212 to 216: two numbers and two catalog strings, which the checker classifies itself.
  • Docs: docs/guided-tour.md §GT4 (the announcement and focus contract), §GT8, §GT9 and §GT10; CHANGELOG.md; README.md.

Verification (local, at the head commit)

  • npx tsc -b, oxlint (39 warnings, the existing baseline), 3,107 unit tests and every check pass; the web, portable and PWA builds pass with the third-party notices unchanged.
  • End-to-end, 36 related spec files in the chromium project (the tour, the new spec, What's new, real dialogs, the menu keyboard, the dialog layer, licences, contextual help, copy wrapping, a template, protected share links, storage, template labels and viewport, the toolbar, and every i18n spec): 689 of 689.
  • The whole mobile project: 106 passed, 4 skipped by design (two desktop-only readouts in canvas-refresh-visual.spec.ts, two chromium-only cases in playback-a11y-background.spec.ts). The new spec's phone cases run in the chromium project at 390 px.
  • The portable file 16 of 16, the production bundle 16 of 16, the PWA 19 of 19.

Before merging

  • A manual check with Windows Narrator in desktop Edge and desktop Chrome (both Chromium) on this pull request's preview: step 1 with its number, title and text once; Next and Back each saying the new step once with focus kept on the button; Back to step 1 leaving focus on Next; Done, Escape and the close button returning to Help; the welcome card's question read as its description. Any step read twice fails it.
  • A real mobile screen reader is not a merge condition and is not checked; the phone is covered by the automated focus and accessibility-tree tests above, in a 390 px Chromium viewport.
  • The full five-shard suite on this pull request's CI.

…(v0.18.2)

Part of #308. Version 0.18.2. Measured on v0.18.1 before the change: the step popover is one dialog whose title and body change in place, the only live text was the `N / 6` position, so a screen reader heard `2 / 6` and nothing else from step 2 on; focus entered on the close control; pressing Back down to step 1 disabled the focused Back button and dropped focus to <body> inside the dialog; and a first-run tour ended by Done left focus on <body>.

The contract, decided by Lumi on 2026-10-06 (docs/guided-tour.md §GT4): step 1 is said by the dialog's name (its `1 / 6` position and its title, both named by aria-labelledby, so the number is not lost) and description (its body, aria-describedby) when focus enters it, on Next. Every later step is said once by one hidden live region inside the popover (polite, atomic), written by the Next or Back press itself, as `N / 6. title. body`; it starts empty, so step 1 is not said twice, and a re-render that is not a step change (a language switch) writes nothing. The visible `N / 6` is no longer live and the title never was. The sentence is its own key, tour.nav.announce, in all 18 languages, with each language's own punctuation (the ideographic full stop in Japanese and Chinese, a space in Thai), not English joined in code. On Back to step 1, focus moves to Next before Back is disabled (disabled stays, not aria-disabled). Every exit (Done, Escape, the close control), first run or replay, lands on the Help button, the overflow button when the toolbar has folded Help into it, or More on a phone, skipping a target that is gone, hidden (visibility included: the overflow button at 1280 px is in the page with visibility: hidden), inert or disabled; only when none of them is usable, the last resort is the top bar's first usable menu button outside the palette, never a palette piece and never <body>. The Welcome card is described by its question; its buttons, order and first focus are unchanged. The phone tour has the same contract and the same layout.

New e2e/tour-announcement.spec.ts (19 tests) records every text the tour's live regions come to hold and every focus loss to <body> from before the app boots. It pins the Welcome card's name and its aria-describedby question; step 1's dialog named `1 / 6` plus its title and described by its body, in Playwright's computation and in Chromium's own accessibility tree, with focus on Next and nothing live; steps 2 to 6 each said exactly once and the announcer as the tour's only live region; Back to step 1 leaving focus on Next; a language switch announcing nothing; and Done, Escape and the close control, first run and replay, at 1280 px, 760 px and 390 px, landing on Help, the overflow button or More, plus the fallback with Help hidden. Run against the code with the two focus fixes reverted, 9 of the 19 fail. Three release-note lines and the step sentence in 18 languages; the 16 other than English and Korean have not been reviewed by a native speaker. The English lines do not say "screen" (the pt-PT audit forbids it: the product has no screen concept). The per-language copy tests move their pinned counts by the four keys and declare the step sentence where it reads the same as English and Escape where each guard asks; the pt-PT audit's differing keys move from 269 to 270 and those outside the password keys from 241 to 242, under the unchanged bound of a quarter of the 970 non-password keys. The ICU argument total moves from 212 to 216 (two numbers and two catalog strings, classified by the checker itself). Docs: docs/guided-tour.md §GT4, §GT8, §GT9 and §GT10, CHANGELOG.md and README.md.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying cozy-loop-studio with  Cloudflare Pages  Cloudflare Pages

Latest commit: 13f3745
Status: ✅  Deploy successful!
Preview URL: https://78d96fc5.cozy-loop-studio.pages.dev
Branch Preview URL: https://fix-tour-announcement.cozy-loop-studio.pages.dev

View logs

@MerciHanrim
MerciHanrim merged commit e787dff into main Oct 6, 2026
10 checks passed
@MerciHanrim
MerciHanrim deleted the fix/tour-announcement branch October 6, 2026 02:31
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