Name a role="img" element the way ARIA actually names one - #34
Draft
bdelanghe wants to merge 1 commit into
Draft
Conversation
`validateTextAlternatives` demanded an `alt` PROP of anything with `role="img"`. But `alt` is a content attribute of <img>/<area>/<input type=image> and exists nowhere else — so the rule was unsatisfiable for its own primary case, a graphic composed of other elements. The three ways a consumer could get past it were all regressions: an invalid `alt` on a <div>, a `role="presentation"` that discards the name, or dropping the role. The svg arm ten lines down was already the control case: it calls hasAccessibleLabel() and accepts aria-label. Reported from a real consumer (#33): a segmented progress bar on robertdelanghe.dev/conformance, correctly named with aria-label, flagged LONE_TEXT_MISSING_ALT with no legal way to satisfy it. WHAT CHANGES. An image needs a NAME; `alt` is one way to carry one. A non-<img> node with role="img" is now checked with hasAccessibleLabel() — the same function the svg, icon-control, canvas and iframe arms already use. A real <img> keeps the stricter reading: alt="" is the documented way to say "decorative", so an empty alt on an otherwise-unnamed image still reports as the distinct EMPTY_ALT_MEANINGFUL rather than collapsing into a missing-alt finding. <img> also stops being flagged when it is named by aria-label/aria-labelledby/ title instead of alt. That is a real relaxation, and the correct one: the accessible-name computation prefers aria-label over alt, and it matches axe's image-alt rule, which accepts all three in alt's place. WHAT DOESN'T. An unnamed <div role="img"> is still an error, and an <img> with no name at all is still an error. Both are covered by new tests, alongside the two positive cases and the aria-labelledby variant. Verified: 336 tests pass, up from 330, none changed. End-to-end through validate() + linkedom on the consumer's exact markup — clean on this branch, LONE_TEXT_MISSING_ALT on main. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011HAtCZXs1B5mUVWf6iTmdp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #33.
validateTextAlternativesdemanded analtprop of anything withrole="img". Butaltis a content attribute of<img>/<area>/<input type=image>and exists nowhere else — so the rule was unsatisfiable for its own primary case, a graphic composed of other elements. Every way past it was a regression: an invalidalton a<div>, arole="presentation"that discards the name, or dropping the role.The
svgarm ten lines down was already the control case: it callshasAccessibleLabel()and acceptsaria-label. Therole="img"arm now does the same.What changes
An image needs a name;
altis one way to carry one.<img>node withrole="img"is checked withhasAccessibleLabel()— the same function the svg, icon-control, canvas and iframe arms already use.<img>keeps the stricter reading:alt=""is the documented way to say "decorative", so an empty alt on an otherwise-unnamed image still reports as the distinctLONE_TEXT_EMPTY_ALT_MEANINGFULrather than collapsing into a missing-alt finding.<img>also stops being flagged when named byaria-label/aria-labelledby/title. That's a real relaxation and the correct one: the accessible-name computation prefersaria-labeloveralt, and it matches axe'simage-altrule, which accepts all three in alt's place. Calling it out explicitly since it's the one behaviour change beyond the reported bug.What doesn't
An unnamed
<div role="img">is still an error, and an<img>with no name at all is still an error. Both have tests, alongside the two positive cases and thearia-labelledbyvariant.Verified
336 tests pass, up from 330 — six added, none changed, none removed.
End-to-end through
validate()+ linkedom on the consumer's exact markup:clean — no findingsmain[error] LONE_TEXT_MISSING_ALT $.children[0].children[0]Heads-up: CI is red on
main, and not because of thisdeno task cifails at its first step on an untouched checkout ofmain:All three are missing a trailing newline, and all three are written by the org harness generator —
standard.ymlhas been red onmainsince at least 2026-08-08 (runs 14, 17, 19).deno fmthere takes no path arguments, so it covers Markdown, JSON and YAML too, which is why lone is hit and baobab (whose task is scoped tosrc tests cli) is not.I have deliberately not included that fix here — it's a different change with a different cause. I'll open it as its own PR so this one can go green, and file the generator side upstream, since reformatting the files by hand only holds until the next harness re-roll rewrites them.
No version bump in
deno.jsonc— release cadence is yours to call.Generated by Claude Code