We failed an accessibility audit on our signup once: unlabeled inputs, an error summary that never got announced, focus that jumped to the top of the page after validation. Retrofitting a11y is miserable, so now I bake it into the generation prompt.
The key was to stop treating accessibility as a checklist appended at the end and instead specify the exact behaviors: programmatic labels, a focus-managed error summary that receives focus on submit, live-region announcements, and a visible focus style that isn't just the browser default I'll later remove. I also make the model output how it would test each requirement.
This produces flows that pass an axe run on the first try. Prompt below. How far do you push automated a11y checks before you trust a generated form?
Build a signup + first-run flow as accessible HTML + minimal JS (no framework). Fields: {FIELDS}. This must pass an automated a11y audit (axe) AND keyboard-only use on the first try.
ACCESSIBILITY REQUIREMENTS (build these in, do not append as an afterthought):
- Every input has a programmatically associated <label> (not placeholder-as-label). Group related fields in <fieldset><legend>.
- Inline validation: on submit, if errors exist, render an error summary at the top, move keyboard focus to it, and link each item to its field. Associate each field's message via aria-describedby and set aria-invalid.
- Use a polite aria-live region for async status ('Checking availability...', 'Account created').
- Visible :focus-visible style with >= 3:1 contrast against the background; never remove outlines without a replacement.
- Logical DOM order == visual order; the flow is fully operable with keyboard only; no focus traps except an intentional modal that returns focus on close.
- Respect prefers-reduced-motion for any step transitions.
DELIVER: the code, then a short TEST PLAN table: requirement -> how to verify (axe rule name, or the exact keyboard steps), so I can confirm each one. Real microcopy, no filler.