valid-lang
Element lang attribute must be syntactically valid
Checks that any element (other than the root <html>) with a non-empty lang attribute uses a syntactically valid language tag.
Applies to. Applies to any element other than the root <html> with a non-empty lang attribute AND at least some non-whitespace "governed text" that actually inherits its language from that element, per ACT de46e4:
- Descendant text/alt is governed by the nearest lang-carrying ancestor only, a nested descendant with its own non-empty lang re-scopes everything inside it, so that subtree no longer counts toward the outer element's applicability (it counts toward the nested element's own, if that one is also being evaluated).
- A non-empty alt attribute on img/area/input[type=image] counts as governed text, the same as a text node.
- Text (or alt) that CSS keeps out of the render tree (display:none, the hidden attribute, ...) does not count. An <area> is drawn by the image that uses its map, so its own display and its map's don't keep its alt out. aria-hidden and offscreen positioning do NOT exempt text, per ACT's own failed examples for both, only actual non-rendering does.
Expectation. The primary language subtag of the lang value (the part before the first hyphen) is a registered language subtag, as ACT de46e4 requires. WCAG 3.1.2 (Language of Parts) requires that when a passage's language differs from the page's default, it is identified programmatically. A tag whose primary subtag is unknown fails to identify a real language at all; a malformed later subtag (lang="en-US_x") still identifies English and passes here, since it is a markup validity error rather than a missing language.
What a finding reports.
reasonCode:DEFAULT_LANG_INVALIDwhen no ancestor (through shadow hosts, <html> included) has a non-empty lang, so this one sets the language its text starts from, as<body lang>does on a page whose <html> has none;ELEMENT_LANG_INVALIDwhen it changes an inherited language. Both fail 3.1.2, as ACT de46e4 does.value: the lang attribute's value, with surrounding whitespace removed.
These data.details fields help to read and reproduce a finding. Apart from reasonCode and the few fields Output schema names as stable, they are not a stable contract: a field may be renamed or dropped in a minor release, so don’t build on them.
Examples
<p lang="fr">Bonjour</p>
"fr" is a syntactically valid BCP 47 language tag.
<p lang="xyz123!!">???</p>
The value isn't valid BCP 47 syntax.