WCAG 3.1.1 · rule: html-has-lang
How to fix a missing or wrong lang attribute
Without a lang attribute a screen reader reads your page in the wrong accent, turning content into noise. Here is the one-line fix and how to get the tag right.
Last updated: · By Paweł Dziura
The one attribute a screen reader reads first
Before a screen reader announces a single word of your content, it needs to know one thing: what language
is this? That answer comes from the lang attribute on the <html> element.
Get it right and the synthesiser loads the correct voice, pronunciation rules, and intonation. Get it
wrong — or leave it off — and it guesses, usually falling back to whatever the user's system default is.
WCAG 2.1 criterion 3.1.1 (Language of Page, Level A) requires that the page's default
human language be programmatically set, and the axe rule html-has-lang checks for it.
What "wrong" actually sounds like
This isn't a theoretical failure — it's viscerally bad. Imagine a German-language page with no
lang attribute, opened by someone whose screen reader defaults to English. The word
"Wichtige" comes out mangled through English pronunciation rules. "Datenschutzerklärung"
becomes an unintelligible sound. An entire paragraph of German read aloud by an English voice engine is,
for a blind user, close to noise. The reverse — English text read by a German voice — is just as broken.
The content is technically all there; it's simply unlistenable. A correct lang attribute is
one line of markup that turns that noise back into speech.
The fix is small and specific
A missing attribute, or an empty or nonsense value, all fail:
<html>
<html lang="">
<html lang="english"> <!-- not a valid language subtag -->
Use a valid BCP 47 language tag — the ISO 639-1 code, optionally with a region:
<html lang="en"> <!-- English -->
<html lang="de"> <!-- German -->
<html lang="en-GB"> <!-- English, British -->
<html lang="pt-BR"> <!-- Portuguese, Brazilian -->
Note the value must be a real code: lang="english" is present but invalid, which is why axe
has a companion rule, html-lang-valid, to catch tags that exist but don't parse.
When part of the page is in another language
The <html> attribute sets the page default. If a passage switches language —
a French pull-quote inside an English article, a product name, a block of legal text in another tongue —
wrap that passage and give it its own lang so the screen reader switches voices mid-page.
This is a separate success criterion (3.1.2, Language of Parts), but it flows from the same idea.
<p>As they say, <span lang="fr">c'est la vie</span>.</p>
How our scanner detects it
The html-has-lang check is one of the most clear-cut we run: we read the
<html> element and confirm a lang attribute exists and is non-empty, then
validate the tag against the BCP 47 subtag registry for html-lang-valid. Missing, empty, or
malformed values are reported directly. The honest limit is that we can verify the tag is
well-formed, not that it's correct: a German page mislabelled lang="en"
passes the automated check because en is a valid tag. Confirming the declared language
actually matches the content is a quick but genuinely human check we flag for manual
review.