Implementation worksheet · 7 min read
A product tour focus restoration test plan
Every way out of a product tour is a focus decision: Escape, the close button, Skip, Done on the last step, a click outside, a route change and the target element disappearing. For each exit, name the element focus must land on, then check it with a keyboard and a screen reader. For modal steps, the WAI-ARIA Authoring Practices dialog pattern gives the default: return focus to the element that opened the dialog, and pick another element that fits the workflow if that element no longer exists. A tour that starts itself has no opener, so the plan must declare a fallback in advance. Focus ending up on the document body fails the plan.
The keyboard acceptance test for tours checks that a tour can be operated without a mouse. This plan narrows to the moment the tour lets go. That moment is easy to get wrong, because the tour layer knows it closed but not what the user was doing before it opened. The actor is a keyboard or screen reader user partway through a task. The system boundary is the tour layer plus the host element it attaches to.
Put it into practice
1. Classify every step as modal or non-modal
A modal step, with the page inert behind it, keeps Tab and Shift+Tab inside while open and has to hand focus back on close. A non-modal hint beside a field shouldn't take focus from the field at all: the APG tooltip pattern, which W3C still marks as work in progress, keeps focus on the triggering element, and a hint containing buttons behaves more like a non-modal dialog. Decide per step, because the restoration rule differs.
2. Record the opener when the tour starts
Store the element that had focus when the tour opened. On close, check that it is still in the document (Node.isConnected) before focusing it. If the tour was started from a menu item inside a menu that has since closed, record the menu's button as the fallback, because the item itself is no longer reachable.
3. Declare a fallback for self-starting tours
A tour fired by page load or an event has no opener. Choose a landing point that suits the task the tour introduced: the main heading, the first field of the feature just explained, or the control the last step pointed at. A heading can take programmatic focus with tabindex="-1" without joining the Tab order.
4. Give every exit path its own row
Escape, close button, Skip, Done, click outside (if allowed), browser Back, in-app route change, target removed and session timeout. Each exit gets an expected landing element. 'Same as close' is a valid entry once you have tested it, not when you have assumed it.
5. Check the landing element can be seen
2.4.11 Focus Not Obscured (Minimum) (Level AA) requires a focused component not to be entirely hidden by author-created content; tour backdrops, sticky headers and the next queued prompt are the usual suspects. 2.4.7 Focus Visible (Level AA) requires a visible focus indicator, so confirm the host's focus ring survives: a tour stylesheet that resets outlines globally will remove it.
6. Remove the target in the middle of the tour
Advance to a step anchored inside a collapsible panel, then close the panel with the keyboard. The tour should skip, end or wait according to its rule, and focus must follow a declared path. Test this case hardest, since the target and the tour's anchor vanish together.
7. Run it with a screen reader and log the announcement
After each exit, note which element was announced and whether the user's place in the page still makes sense. Record browser and screen reader versions. Re-run after any change to the tour library, the host's routing or the host's focus styles.
Exit path test plan
Copy this structure into your review document and record your observed result for each row.
| Exit path | Expected landing | Illustrative result | Verdict |
|---|---|---|---|
| Escape on a modal step | The Help menu button that started the tour | Landed on the Help button | Pass |
| Close button | The Help menu button | Landed on the Help button | Pass |
| Skip tour | The Help menu button | Landed on the document body | Fail: no fallback wired to Skip |
| Done on the final step | The Export control the last step described | Landed on Export | Pass: workflow choice documented |
| Self-started tour closed | Main heading with tabindex="-1" | Landed on the heading | Pass |
| Target panel closed mid-tour | The panel's toggle button | Landed on the toggle | Pass |
| In-app route change | Heading of the new route; tour torn down | Tour stayed open over the new page | Fail: teardown missing |
| Opener removed before close | Declared fallback: the section heading | Landed on the section heading | Pass |
| Landing element under a sticky header | The same landing element, scrolled into view | Focused control entirely hidden | Fail: 2.4.11, Level AA |
A failure worth checking
The auto-started welcome tour. It opens on first load, so there is no opener to return to, and its close handler simply removes the layer. When a focused element is removed, document.activeElement becomes the body. A screen reader may announce nothing useful, and where the next Tab press goes depends on the browser. The user was halfway through reading the dashboard and is now somewhere unknown. The fix is a declared, tested fallback for each self-starting tour, not a cleverer default.
Common questions
Must focus go back to the opener after the Done step?
Not necessarily. The APG dialog pattern allows focus to move to a different element when the task completed in the dialog leads directly into a next step. If the last step pointed at Export, landing there is defensible. Write the choice into the plan so testers know which result counts as correct.
Does WCAG require focus restoration?
No success criterion names it. The ones usually at stake are 2.4.3 Focus Order (Level A), 2.1.2 No Keyboard Trap (Level A), 2.4.7 Focus Visible (Level AA) and 2.4.11 Focus Not Obscured (Minimum) (Level AA). The APG patterns are guidance, not normative requirements. This plan tests behavior against those; it doesn't certify conformance.
Basis and scope
This is a proposed implementation method using illustrative examples, not a measured benchmark or a customer case study. Prepared with AI assistance. Validate product-specific behavior against current documentation and your own test environment.