Accessible Language Switcher: WCAG Requirements
An accessible language switcher is operable by keyboard, has a clear accessible name, identifies the page language with lang on the <html> element (WCAG 3.1.1), marks each language label with its own lang (3.1.2), and does not change the page unexpectedly when a control receives focus or changes value. Plain links in a labelled <nav> meet most of these needs with little code.
Which WCAG criteria apply to a language switcher?
The wording below is taken from the W3C "Understanding WCAG 2.2" pages. Levels are A or AA; conformance to AA is the common target in laws and procurement, though which standard applies to you depends on your jurisdiction.
| Criterion | Level | What it says (short) | Why it matters here |
|---|---|---|---|
| 3.1.1 Language of Page | A | The default human language of each web page can be programmatically determined. | Set lang on <html> for every language version. |
| 3.1.2 Language of Parts | AA | The human language of each passage or phrase can be programmatically determined, except for proper names, technical terms, words of indeterminate language, and words or phrases that have become part of the vernacular of the surrounding text. | Each language label (Deutsch, Français) is a foreign-language phrase. |
| 2.1.1 Keyboard | A | All functionality is operable through a keyboard interface. | The whole switcher must work without a mouse. |
| 2.4.7 Focus Visible | AA | Any keyboard operable interface has a mode where the focus indicator is visible. | Never remove the outline without replacing it. |
| 2.5.3 Label in Name | A | For components whose labels include text or images of text, the accessible name contains the text presented visually. | A visible "Deutsch" should not have an accessible name that omits it. |
| 3.2.2 On Input | A | Changing the setting of a UI component does not automatically cause a change of context unless the user has been advised beforehand. | Relevant if you use a <select>. |
| 4.1.2 Name, Role, Value | A | For all UI components, name and role can be programmatically determined, and state changes are available to assistive technology. | Custom dropdowns need correct roles and states. |
| 2.5.8 Target Size (Minimum) | AA | The size of the target for pointer inputs is at least 24 by 24 CSS pixels, except in listed cases. | Tap targets for language links. |
Target size is part of WCAG 2.2, so it will not appear in checklists built only on 2.1.
How do you set the page language correctly?
Put the language of the page on the root element, not on <body>. W3C's guidance is to always use a lang attribute on the html tag; descendants inherit it. Use valid BCP 47 tags (see language and region codes):
<!doctype html>
<html lang="de" dir="ltr">
Rules of thumb:
- One
langper page version, matching the language of the main content, and the same language you declare in hreflang annotations. - For right-to-left languages also set
dir="rtl".langalone does not set direction; the RTL guide covers this. - Do not rely on
<meta http-equiv="Content-Language">; W3C advises against it, and the in-page declaration takes precedence over HTTP-supplied language information. - Update
langwhen the translated page is generated. A German page that still sayslang="en"makes screen readers use the wrong pronunciation rules, which is a real failure of 3.1.1.
A note on SEO: Google states it does not use hreflang or the HTML lang attribute to detect the language of a page. lang is still necessary for accessibility, so do it for users, not for rankings.
How do you mark up the language labels?
In an English page, the label "Deutsch" is a passage in German. WCAG 3.1.2 asks for it to be programmatically identifiable, so use lang on the element holding the label. W3C's own example is <span lang="es">Español</span>.
<nav aria-label="Language">
<ul>
<li><a href="/en/" lang="en" hreflang="en" aria-current="true">English</a></li>
<li><a href="/de/" lang="de" hreflang="de">Deutsch</a></li>
<li><a href="/es/" lang="es" hreflang="es">Español</a></li>
</ul>
</nav>
Two details:
- Put
langon the link itself or on a<span>inside it. If you add atitleor visually hidden text written in the current page's language, keep it on the<a>, not inside an element carrying the targetlang, so it is not read in the wrong voice (this follows W3C's guidance on language links). - The
hreflangattribute on an<a>element is part of HTML and describes the linked resource's language. Treat it as informational metadata: it is not the same as thehreflangannotations in<head>that search engines use, and it does not make a link accessible by itself. We could not find a WCAG requirement for it, so the value is mostly consistency.
Links or a select element?
| Pattern | Strengths | Watch out for |
|---|---|---|
List of links in <nav> |
Works without JavaScript, crawlable, native keyboard and screen-reader behaviour, easy to mark aria-current |
Long lists need a collapse control |
Native <select> plus "Go" button |
Compact, familiar on mobile | Needs a button; changing the value must not navigate by itself without warning |
| Custom dropdown (button + popup) | Visual freedom | You must build keyboard, focus and ARIA states yourself |
On <select>: the WCAG 3.2.2 Understanding page says changing the selected option counts as changing the setting of a component, so it should not automatically cause a change of context such as navigating to a new page unless users are advised beforehand. Sufficient techniques include a separate button to perform the action (H84). A language switch navigates to a new page, so a select that does this on change is a classic 3.2.2 problem.
For a custom dropdown, the WAI-ARIA Authoring Practices "disclosure" pattern is a good basis: a <button> with aria-expanded true or false toggles a list of links, and both Enter and Space activate the button. aria-controls is optional. Avoid inventing role="menu" or listbox for what is really a short list of links; those roles bring extra keyboard expectations you then have to implement.
What should keyboard and screen-reader behaviour be?
- Tab order follows visual order, and the switcher is reachable in a reasonable number of tab stops. Consider whether a "skip to content" link helps users get past it.
- Name: give the
<nav>a label such asaria-label="Language", written in the page language. The visible button text should be contained in its accessible name (2.5.3), so do not set anaria-labelthat omits the visible word. - State: expose the current language with
aria-current="true"and, for collapsible lists,aria-expanded. - Focus: visible focus indicator with sufficient contrast; when a disclosure closes with Escape, return focus to its button (common practice; not a stated WCAG requirement).
- Announcements: after navigation the screen reader announces the new page title, so translate
<title>as well.
What else should you test?
Test with a keyboard only, then with at least one screen reader on each major platform you support. Check that the new page loads with the right lang, that the label pronounces correctly, and that the 24 by 24 pixel target-size rule is met or that a listed exception applies. Our UX best-practices article covers placement and labelling, which also affect accessibility.
Key takeaways
- Set a correct
langon<html>for every language version (WCAG 3.1.1, Level A), and adddirfor right-to-left languages. - Mark each language label with its own
lang(3.1.2, Level AA); proper names and words absorbed into the surrounding language are exceptions. - Prefer a
<nav>with real links; if you use a<select>, add a button so a change does not navigate unexpectedly (3.2.2). - Ensure keyboard operation, visible focus, matching visible and accessible names, and adequate target size.
langis for accessibility, not a Google ranking signal: Google says it does not use it to detect page language.
Sources
- W3C: Understanding SC 3.1.1 Language of Page – wording and level of 3.1.1
- W3C: Understanding SC 3.1.2 Language of Parts – wording, level and exceptions of 3.1.2
- W3C: Understanding SC 3.2.2 On Input – select elements and changes of context
- W3C: Understanding SC 2.5.8 Target Size (Minimum) – 24 by 24 CSS pixel rule
- W3C Internationalization: Declaring language in HTML – lang on html, language links, Content-Language
- Google Search Central: Localized versions of your pages – Google does not use hreflang or lang to detect language
Frequently asked questions
Which WCAG criteria apply to a language switcher?
Mainly 3.1.1 Language of Page (A), 3.1.2 Language of Parts (AA), 2.1.1 Keyboard (A), 2.4.7 Focus Visible (AA), 3.2.2 On Input (A), 2.5.3 Label in Name (A), 4.1.2 Name, Role, Value (A) and, in WCAG 2.2, 2.5.8 Target Size (Minimum) (AA).
Do I need a lang attribute on each language name in the switcher?
Usually yes. A label such as Deutsch on an English page is a passage in another language, which WCAG 3.1.2 asks you to identify programmatically, with exceptions such as proper names and words absorbed into the surrounding language. Adding lang to each label is cheap and helps screen readers pronounce it.
Should a language switcher be a select element or a list of links?
Either can be accessible. Links are simplest because they navigate without scripting and need no extra state. If you use a select, do not navigate on change without warning, because WCAG 3.2.2 treats that as an unexpected change of context unless users are told beforehand; add a separate Go button.
Does the html lang attribute affect SEO?
Google says it does not use hreflang or the HTML lang attribute to detect a page's language; it uses its own algorithms. The lang attribute is still required for accessibility and helps browsers, translation tools and screen readers, so set it correctly regardless.