Next.js: Add lang attribute to html for better accessibility

Created on 22 Oct 2019  ·  19Comments  ·  Source: vercel/next.js

Feature request

html tag accepts lang attribute that is, according to MDN, very important for accessibility and accessible technologies like screen readers.

Providing a lang attribute with a valid IETF identifying language tag on the element will help screen reading technology determine the proper language to announce.

Describe the solution you'd like

Add lang="en" by default and provide a simple way to configure the language for the whole project.

Describe alternatives you've considered

We've ended overriding the _document.js as of https://github.com/zeit/next.js#custom-document but not providing this by default contributes to even worse web accessibility situation.

Additional context

Google Chrome shows "Translate this page" dialog without the lang set.

story feature request needs investigation

Most helpful comment

It would be nice to not have to override pages/_document.js and just add something to next’s config.

All 19 comments

IMHO setting lang="en" by default can make things worse for non-English Next.js websites. Setting it in _document.js seems to be the right way. This is what I do and I don't feel bothered 🤷‍♂️

I assume most next.js user don't bother overriding _document.js.

Assuming all pages are english would be wrong imo. For reference there's a large number of Next.js sites in basically every major language you can think of.

Making it easier to configure something like that would be interesting to pursue. cc @devknoll let's keep this in mind with the next/head deprecation.

Thinking more broadly, react-helmet provides a facility for supplying arbitrary attributes to html and body within its equivalent of Head on any page.

To come back to my earlier comment, RFC for deprecating next/head is here: #8981

this fails on lighthouse CI with a default create-next-app and seems easy to fix

It would be nice to not have to override pages/_document.js and just add something to next’s config.

+1 lang is important

+1 it's important

Please don't spam the thread with +1. Use the GitHub emoji reaction system to add a 👍 on the initial issue.

Perhaps this is a bit out of scope, but for multi-domain deployments (.com, .nl, .pt) it would also be kind of nice to add the lang tag without having to implement a custom server either.

Anyone managed to set <Html lang={someLang}> when using getServerSideProps or getStaticProps when the language changes between pages? Right now the _document.js is only set on first load, from there it is not set again. That means the language prop from my pages will never change in the _document.js file.

Right now i am using getServerSideProps like this. Where i set the language on the page, and then extract the language in _document.js from __NEXT_DATA__ and set it on the <Html lang={langHere}>

export async function getServerSideProps(context) {
  const pageContent = await getSomePageContent(context.params)

  return {
    props: {
      language: getLanguageFromParams(context.params),
      pageContent,
    },
  }
}

@timneutkens The documentation does not mention any solution on how to set the language again?

Using getServerSideProps will lose the benefit of static optimization unless you're using it already.

The following approach is to set different lang attributes for different pages using _document.js's getInitialProps for SEO.

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    const { pathname } = ctx;
    const lang = pathname.startsWith("/de") ? "de" : "en";
    return { ...initialProps, lang };
  }

  render() {
    const { lang } = this.props;
    return (
      <Html lang={lang}>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

Then, update the lang attribute with the help of useRouter hook in _app.js for client-transitions:

function MyApp({ Component, pageProps }) {
  const { pathname } = useRouter();
  const lang = pathname.startsWith("/de") ? "de" : "en";
  useEffect(() => {
    document.documentElement.lang = lang;
  }, [lang]);

  return <Component {...pageProps} />;
}

But this approach would only work if browsers and screen readers will pick up dynamically set lang attribute.

Edit dynamic-html-lang-property-in-statically-generated-next-js-pages

Is there any recommendation on how to set the HTML language when using getstaticprops / path? We can prerender all of our pages and have the active language set as param. page.de/en/products/XXX or page.de/de/products/XXX - so the language is available as prop. Just curious if we could set the language during static build time.

Using getServerSideProps will lose the benefit of static optimization unless you're using it already.

The following approach is to set different lang attributes for different pages using _document.js's getInitialProps for SEO.

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    const { pathname } = ctx;
    const lang = pathname.startsWith("/de") ? "de" : "en";
    return { ...initialProps, lang };
  }

  render() {
    const { lang } = this.props;
    return (
      <Html lang={lang}>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

Setting through getInitialPropswon't work for dynamic routes.

FYI, I developed a work around on my project for this.
I used the opengraph meta "og:locale" to define the local for each page and then in my custom Document I search it.
This is my code :

```
export default class CustomDocument extends Document static async getInitialProps(ctx: DocumentContext) {
const initialProps: DocumentInitialProps = await Document.getInitialProps(ctx);
const ogLocaleMeta = initialProps.head
? initialProps.head.find((e) => e && e.type === "meta" && e.props.name === "og:locale")
: null;
return { ...initialProps, lang: ogLocaleMeta ? localeToLang[ogLocaleMeta.props.content] : null };
}

render() {
return (
```

Hope it can helps someone else :)

document.documentElement.lang = 'yourlang'

You can add this yourself in _document.js & the new internationalization feature handles it automatically: https://nextjs.org/docs/advanced-features/i18n-routing#search-engine-optimization

I think we can close this @Timer?

Was this page helpful?
0 / 5 - 0 ratings