For AI agents: llms.txt is a short guide that sends you to the rules your problem needs, and rules.json holds every rule of this playbook as JSON.
Recommended
Show where people are in a multi-step form
Put the step number and the total in the title and heading of each step, such as "Step 2 of 4". Give each step its own address, and keep every answer when people go back.
How to do it
Write the progress first in the title, such as "Step 2 of 4 - Shipping address". List the steps in an ordered list, link the finished ones, and mark the current one with aria-current="step". Keep the step in the address, as state in the address describes, so Back and reload work. Save each step's answers when people move on. Never ask again for what an earlier step collected, as redundant entry requires. End with a review step before anything is charged or sent.
Examples
Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.
TypeScript example
export function showStep(step: number, steps: string[], form: HTMLFormElement) {
const title = `Step ${step} of ${steps.length} - ${steps[step - 1]}`;
document.title = `${title} | Example Shop`;
form.querySelector('h1')!.textContent = title;
history.pushState({ step }, '', `?step=${step}`);
form.querySelectorAll('.steps a').forEach((link, index) => {
if (index === step - 1) link.setAttribute('aria-current', 'step');
else link.removeAttribute('aria-current');
});
}
Python example
from playwright.sync_api import expect
def test_back_keeps_earlier_answers(page):
page.goto("https://staging.example.com/checkout?step=1")
expect(page).to_have_title("Step 1 of 4 - Contact | Example Shop")
page.get_by_label("Email").fill("ada@example.com")
page.get_by_role("button", name="Next").click()
expect(page).to_have_url("https://staging.example.com/checkout?step=2")
page.go_back()
expect(page.get_by_label("Email")).to_have_value("ada@example.com")
expect(page.get_by_role("link", name="Contact")).to_have_attribute("aria-current", "step")
How to check
A browser test fills steps 1 and 2, presses the browser's Back button, and finds step 1 with its values and its own address. It reloads step 2, and the values are still there. Every step's title starts with "Step N of M".
Sources
- W3C WAI tutorial on multi-page forms
- WCAG 2.2 criterion 3.3.7 Redundant Entry
- WAI-ARIA 1.2 on aria-current
Related rules
- Keep screen state in the address in App interface
- Never ask for the same thing twice in Website
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/app-ui/forms/multi-step-forms">Agent Wranglers app interface playbook</a>. In code you write, add a comment next to it with the same link.