N
Nuxt5d ago
Kay

htmlAttrs.lang not working

Hi, I have a weird bug, not sure if it’s worth opening a GitHub issue for it. In my nuxt.config.ts, I’m setting the HTML lang="fr" attribute like this:
export default defineNuxtConfig({
compatibilityDate: '2024-11-01',
future: {
compatibilityVersion: 4,
},

app: {
head: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1',
htmlAttrs: { dir: 'ltr', lang: 'fr' },
[...]
},
},

modules: [
'@nuxt/ui',
'nuxt-auth-utils',
'@vueuse/nuxt',
'@nuxtjs/seo',
'@nuxt/image',
'@nuxtjs/critters',
'@nuxt/scripts',
],

[...]
})
export default defineNuxtConfig({
compatibilityDate: '2024-11-01',
future: {
compatibilityVersion: 4,
},

app: {
head: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1',
htmlAttrs: { dir: 'ltr', lang: 'fr' },
[...]
},
},

modules: [
'@nuxt/ui',
'nuxt-auth-utils',
'@vueuse/nuxt',
'@nuxtjs/seo',
'@nuxt/image',
'@nuxtjs/critters',
'@nuxt/scripts',
],

[...]
})
Yet, at build time, the DOM has lang="en". I even tried using useHead({ htmlAttrs: { lang: 'fr' } }) in my ./app/app.vue, but I still get lang="en" in the DOM. Could it be that Nuxt uses an environment variable to determine the DOM language? What’s really strange is that I have another site that builds correctly and respects the language setting. Maybe the issue is caused by a new version of Nuxt?
{
"dependencies": {
"@floating-ui/vue": "^1.1.6",
"@internationalized/date": "^3.7.0",
"@nuxt/image": "1.10.0",
"@nuxt/scripts": "^0.11.7",
"@nuxt/ui": "^3.0.1",
"@nuxtjs/critters": "^0.9.0",
"@nuxtjs/seo": "^3.0.3",
"@vueuse/core": "^13.2.0",
"@vueuse/nuxt": "^13.2.0",
"chart.js": "^4.4.9",
"chartjs-plugin-datalabels": "^2.2.0",
"ipx": "3.0.1",
"nuxt": "~3.17.4",
"nuxt-auth-utils": "^0.5.17",
"nuxt-seo-utils": "^7.0.12",
"quill": "^2.0.3",
"quill-auto-detect-url": "1.0.0-alpha.1",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.16",
"vite-plugin-vue-tracer": "0.1.2",
"vue": "^3.5.13"
}
}
{
"dependencies": {
"@floating-ui/vue": "^1.1.6",
"@internationalized/date": "^3.7.0",
"@nuxt/image": "1.10.0",
"@nuxt/scripts": "^0.11.7",
"@nuxt/ui": "^3.0.1",
"@nuxtjs/critters": "^0.9.0",
"@nuxtjs/seo": "^3.0.3",
"@vueuse/core": "^13.2.0",
"@vueuse/nuxt": "^13.2.0",
"chart.js": "^4.4.9",
"chartjs-plugin-datalabels": "^2.2.0",
"ipx": "3.0.1",
"nuxt": "~3.17.4",
"nuxt-auth-utils": "^0.5.17",
"nuxt-seo-utils": "^7.0.12",
"quill": "^2.0.3",
"quill-auto-detect-url": "1.0.0-alpha.1",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.16",
"vite-plugin-vue-tracer": "0.1.2",
"vue": "^3.5.13"
}
}
8 Replies
kapa.ai
kapa.ai5d ago
Hi @Kay. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the provided knowledge sources, setting the HTML lang attribute in Nuxt should work by specifying it in the app.head.htmlAttrs property in your nuxt.config.ts, as you have done:
export default defineNuxtConfig({
app: {
head: {
htmlAttrs: { lang: 'fr', dir: 'ltr' }
}
}
})
export default defineNuxtConfig({
app: {
head: {
htmlAttrs: { lang: 'fr', dir: 'ltr' }
}
}
})
This is the documented approach for setting static attributes like lang and dir on the <html> element, and it should be respected at build time unless overridden elsewhere SEO and Meta. If you use useHead in your app.vue, it should also update the htmlAttrs reactively:
<script setup lang="ts">
useHead({
htmlAttrs: {
lang: 'fr'
}
})
</script>
<script setup lang="ts">
useHead({
htmlAttrs: {
lang: 'fr'
}
})
</script>
Again, this is the recommended way to set or override head attributes programmatically useHead composable. Possible reasons for lang="en" still appearing: - If you are using a module or composable that manages i18n (such as @nuxtjs/i18n or Nuxt UI's locale system), it may override the lang attribute dynamically based on the detected or default locale. For example, Nuxt UI and i18n modules often set lang and dir on the <html> element based on the current locale, and this can override your static config Nuxt UI I18n. - If you use useHead or useHeadSafe elsewhere in your app, those calls can override the htmlAttrs set in nuxt.config.ts, since the most recent or most specific call takes precedence useHead composable. - There is no mention in the knowledge sources of Nuxt using an environment variable to set the lang attribute by default. What to check: - If you are using @nuxtjs/i18n or Nuxt UI's i18n features, check if they are setting the lang attribute based on the current locale. In such cases, the lang attribute will be set dynamically, and your static config will be overridden Nuxt UI I18n. - Make sure you are not calling useHead or useHeadSafe elsewhere with htmlAttrs: { lang: 'en' }. - If you want to set lang dynamically based on the current locale, you should use useHead with a computed value, as shown in the Nuxt UI documentation:
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useHead } from '@unhead/vue'
import * as locales from '@nuxt/ui/locale'

const { locale } = useI18n()

const lang = computed(() => locales[locale.value].code)
const dir = computed(() => locales[locale.value].dir)

useHead({
htmlAttrs: {
lang,
dir
}
})
</script>
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useHead } from '@unhead/vue'
import * as locales from '@nuxt/ui/locale'

const { locale } = useI18n()

const lang = computed(() => locales[locale.value].code)
const dir = computed(() => locales[locale.value].dir)

useHead({
htmlAttrs: {
lang,
dir
}
})
</script>
Dynamic direction Summary:
If you are using i18n or Nuxt UI's locale features, they are likely overriding your static lang setting. This is expected behavior for dynamic, locale-driven apps. If you want a static lang, ensure no i18n or UI modules are setting it dynamically. If you want it to follow the current locale, use useHead with a computed value as shown above. If none of these apply and the issue persists, the knowledge sources do not provide further troubleshooting steps for this specific scenario. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5d ago
<@258334777046859776> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Kay
KayOP5d ago
I think the issue is with @nuxtjs/seo. If I remove it, my html attribute lang="fr" works.
johntanzer
johntanzer5d ago
That is strange unless there is another version of head running after cc @harlan
Kay
KayOP5d ago
Well, I removed @nuxt/seo for now. As it works without it.
harlan
harlan5d ago
you need to define your locale if you're using nuxt seo it could read this value as a default though
export default defineNuxtConfig({
site: {
url: 'https://example.com',
name: 'Awesome Site',
defaultLocale: 'fr',
}
})
export default defineNuxtConfig({
site: {
url: 'https://example.com',
name: 'Awesome Site',
defaultLocale: 'fr',
}
})
probably need to improve the docs for that
Kay
KayOP5d ago
Alright, thank you. Definitely. That would be awesome.
harlan
harlan5d ago
if you can make a github issue i'll make sure it happens 🙏

Did you find this page helpful?