Prompting Claude for accessible HTML
Accessibility has to be a stated requirement, not an assumption
Asked to build a UI with no mention of accessibility at all, Claude — like most code generation —
will often produce something that looks correct but skips real accessibility requirements: a
clickable div instead of a real button, an image with no alt text, a form with no associated
labels, focus states that were never considered because nothing in the request asked for them.
None of this is a quality failure specific to how the request was handled — it's what happens when
an important requirement is left implicit rather than stated, the same way any unstated requirement
tends to get skipped by any code generation process, human or otherwise.
Ask for the right elements, not just the right accessibility attributes
A common half-measure is layering ARIA attributes onto elements that are the wrong semantic choice
to begin with — an ARIA role bolted onto a div to make it announce as a button, rather than
simply using a real <button> element that gets that behaviour correctly for free. Native HTML
elements carry a large amount of correct accessibility behaviour automatically; ARIA exists to fill
genuine gaps native HTML can't cover, not to patch a wrong element choice after the fact. Ask
explicitly for semantic, native elements first, and reserve ARIA for the cases that genuinely need
it rather than treating it as a default layer to sprinkle over whatever markup came out first.
Keyboard navigation is easy to leave unverified
A UI that looks complete and passes a visual review can still be effectively unusable without a mouse — focus order that jumps unpredictably, an interactive element that never receives visible focus, a custom component that doesn't respond to keyboard input at all despite behaving correctly with a mouse. This category of problem is specifically invisible to a purely visual check, which is exactly why it survives so often — reviewing generated markup by clicking through it will not catch a keyboard-navigation failure, only an actual keyboard-only pass through the same interface will.
Colour and contrast need an explicit check, not a glance
A generated UI can look fine to a quick glance and still fail a real contrast requirement, particularly with lighter text on lighter backgrounds or colour combinations chosen more for aesthetic preference than for legibility. This is a checkable, objective property, not a subjective call, and it deserves a specific pass rather than folding it into a general "does this look good" review. See using Claude to audit a design for contrast for that check specifically.
Testing what you asked for, not just trusting the output
Because accessibility requirements are exactly the kind of thing that's easy to state in a prompt and still not fully realise in the output, treat a request for accessible markup as a starting point for verification, not a guarantee. Run the actual output through a real accessibility check — automated tooling for the mechanical checks, and a genuine keyboard pass for the interactive behaviour automated tools can't fully assess — rather than trusting that stating the requirement was enough to satisfy it on its own.
Building accessibility requirements into your reusable prompt template
If you're generating UI repeatedly, the accessibility requirements worth stating are largely consistent across requests — semantic elements over ARIA-patched divs, keyboard operability, real labels. Rather than restating them fresh in every prompt, folding them into a standing template or reusable instruction saves effort and, more importantly, prevents the requirement from being forgotten on the one request where you were focused on something else and didn't think to restate it.
Iterating specifically on accessibility failures
When a review does turn up a specific accessibility gap, feed that gap back precisely — which element, which requirement it fails, what correct behaviour should look like — rather than a general "make this more accessible" follow-up. A specific correction produces a specific fix; a vague one tends to produce a scattered pass across the whole component that may or may not land on the actual problem you found.
Verified 2026-08-08 against ClaudeHow facts module (src/data/facts/) — see /about/#accuracy.