Without a language declaration, screen readers guess the page language based on user settings. If they guess wrong, content becomes incomprehensible.
The lang attribute on the <html> element tells browsers and assistive technologies what language the page content is in. Screen readers use this to load the correct pronunciation rules, speech patterns, and voice.
When the lang attribute is missing, a screen reader assumes the user's default language. A French page read with English pronunciation rules produces nonsensical audio. Even for English pages, missing the lang attribute can affect hyphenation, quotes, and other language-specific features.
<html> elementlang attribute exists with a valid valueQuick console check:
const lang = document.documentElement.lang
if (!lang) {
console.error('HTML element is missing lang attribute')
}
else {
console.log('Page language:', lang)
}
<!DOCTYPE html> should be <html lang="...">Add the lang attribute to your <html> element:
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
...
</body>
</html>
Use BCP 47 language tags:
<!-- Basic language codes -->
<html lang="en"> <!-- English -->
<html lang="es"> <!-- Spanish -->
<html lang="fr"> <!-- French -->
<html lang="de"> <!-- German -->
<html lang="ja"> <!-- Japanese -->
<html lang="zh"> <!-- Chinese -->
<!-- With regional variants -->
<html lang="en-US"> <!-- American English -->
<html lang="en-GB"> <!-- British English -->
<html lang="pt-BR"> <!-- Brazilian Portuguese -->
<html lang="zh-Hans"> <!-- Simplified Chinese -->
<html lang="zh-Hant"> <!-- Traditional Chinese -->
When content switches language within the page, use lang on specific elements:
<html lang="en">
<body>
<p>The French phrase <span lang="fr">c'est la vie</span> means "that's life".</p>
<blockquote lang="de">
Die Grenzen meiner Sprache bedeuten die Grenzen meiner Welt.
</blockquote>
<p>— Ludwig Wittgenstein</p>
</body>
</html>
Screen readers will switch pronunciation rules for the marked sections.
nuxt.config.ts:export default defineNuxtConfig({
app: {
head: {
htmlAttrs: {
lang: 'en'
}
}
}
})
<script setup>
// In your layout or page
const { locale } = useI18n()
useHead({
htmlAttrs: {
lang: locale.value
}
})
</script>
@nuxtjs/i18n, this is handled automatically based on the current locale.// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
// app/[locale]/layout.tsx
export default function LocaleLayout({ children, params }) {
return (
<html lang={params.locale}>
<body>{children}</body>
</html>
)
}
_document.js:// pages/_document.js
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
<html> element has a [lang] attribute" audit should passconst lang = document.documentElement.lang
console.log('Lang attribute:', lang || 'MISSING')
console.log('Valid:', /^[a-z]{2,3}(-[A-Za-z]{2,4})?$/.test(lang))
<html>, not <body>. The lang attribute on body is ignored by most tools.<html lang="english"> is invalid. Use proper BCP 47 codes like en.<html lang=""> fails the audit. Must contain a valid code.lang="en" on a French page is worse than no lang at all. Screen readers will mispronounce everything.en-US vs en-GB, pt-PT vs pt-BR.HTML lang issues often appear alongside:
Missing lang attributes often occur in error pages, legacy templates, or dynamically generated pages that bypass your main layout. Unlighthouse scans every page on your site and flags any missing lang attributes, ensuring consistent accessibility across all routes.