Skip to content

LanguageSelector

C-52 · Components · Navigation

All elements · LanguageSelector on the Components page

Last checked 2026-10-22 · Awaiting approval · Accessibility tests

Copies the bun run a11y:approve command for LanguageSelector.

LanguageSelector

C-52WCAG 2.2 AA · Passed

Lets the user read the app in another language (USWDS Language selector). A button naming the current language opens a Menu of languages, each written in its own language and script with its lang, and glossed in the page's language; an app with two languages uses a single link to the other one. UI only: choosing a language here changes the button, not the page.

Axis Values
Form menu (__trigger + __menu) · toggle (__toggle, a link to the other language)
__trigger › __current[lang] a C-01 Button with aria-haspopup="menu"; a visually hidden "Language:" and the current language in its own name
__menu › .qf-menu__item[role="menuitemradio"][aria-checked] one item per language; the current one checked
.qf-menu__label[lang] · [dir="rtl"] · .qf-menu__description the language's own name, its lang (and dir for right-to-left scripts), and its name in the page's language
__toggle[lang][hreflang] the other language's own name, as a link
Menu: click to open and choose; static copy alongside
Two-language toggle: on the English page · on the Spanish page

Guidance

When to use

  • Let users switch the app's interface language when it is offered in more than one, for example to meet a limited-English-proficiency plan (Executive Order 13166).
  • Use the menu form for three or more languages, and the two-language toggle when there are exactly two.
  • Put it in the same place on every page, usually the shell's utility strip at the top end, so users who cannot read the current language can still find it.

When to consider something else

  • When the choice is a per-document property, such as the language of a document's text, use a Select in its properties instead. See Select.
  • When the setting is part of a user's profile with other preferences, put a Select on the profile page and keep this control for quick switching. See Select.
  • When only one page or document is translated, link to its translation in the page instead of offering an app-wide switch.

Usability

Do
  • Write every language in its own language and script (Español, Tiếng Việt, 中文, العربية), so a reader of that language recognizes it.
  • Add the name in the page's language as the item's description (Spanish), so others can tell what each one is.
  • Show the current language on the button, in that language, and mark it checked in the menu.
  • Keep the order stable: the page's language first, then the rest in a fixed order (by number of users, or alphabetically by English name).
  • Use the language icon beside the name; it is recognized across languages.
Don’t
  • Don't use flags; a flag is a country, not a language.
  • Don't translate the language names into the current language only; a Vietnamese reader looking for "Tiếng Việt" may not recognize "Vietnamese".
  • Don't open the selector by hover alone.
  • Don't hide it in a settings page; users who cannot read the current language cannot navigate there.

Accessibility

Keyboard

LanguageSelector keyboard
Keys Action
Enter, Space or Arrow Down On the button, opens the menu and moves focus to the first language (as Menu).
Arrow Down / Arrow Up Moves between languages, wrapping at the ends.
Home / End Moves to the first or last language.
Enter or Space Chooses the focused language, closes the menu and returns focus to the button.
Escape Closes the menu without a change and returns focus to the button.
Tab On the toggle, it is one link in the Tab order; Enter follows it.

Roles and names

  • The button is a C-01 Button with aria-haspopup="menu", aria-expanded and aria-controls; its name is a visually hidden "Language:" plus the current language, e.g. "Language: English".
  • The menu is role="menu" with an aria-label ("Language"); each language is a menuitemradio with aria-checked, exactly one checked.
  • Each language's own name carries lang (and dir="rtl" for Arabic, Hebrew, Persian and Urdu) so screen readers pronounce it in that language (3.1.2 Language of Parts); the trigger's current name carries the same.
  • The description in the page's language has no lang of its own.
  • The toggle is a link (a) with lang and hreflang set to the other language; it navigates, so it is not a button.
  • Once the language changes, the app must update lang (and dir) on <html> (3.1.1 Language of Page).

Focus

  • Opening the menu moves focus into it; choosing or Escape returns focus to the button.
  • The button, items and toggle show the shared focus ring.

Other requirements

  • Right-to-left names are isolated (unicode-bidi: isolate), so they do not reorder the button's icon and chevron, and they line up with the other names in the menu.
  • The button is a full control height (2rem) and menu items at least 2rem tall, meeting 2.5.8.
  • The fonts must cover every script offered; Avenir Next has no Chinese or Arabic glyphs, so those names fall back to the system font.
  • This element is UI only in the design system: wiring it to translations, saving the choice and reloading strings is the app's job.

Test your implementation too. This guidance covers the element as specified here. How a screen composes it (labels, order, announcements) still needs its own keyboard and screen reader check.

Accessibility tests

WCAG 2.2 AA · Passed

Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.

LanguageSelector test checklist
Area Automated A person checks
General Passed Color is never the only cue, text alternatives say the same thing as the graphic, and the element reads the same in the light and the dark theme.
Zoom Passed At 200% zoom, at 320 CSS pixels wide and with the WCAG text-spacing overrides, nothing is lost, clipped or overlapping.
Keyboard Passed Every row of the Keyboard table works, focus is always visible and never trapped, and the tab order follows the reading order. (6 rows)
Screen reader Passed With NVDA or JAWS on Windows and VoiceOver on macOS, names, roles and states are announced as Roles and names says, and changes are announced once. (6 items)

Approving. When the checklist passes on the checked run, record it with bun run a11y:approve -- language-selector --by "Your name" and commit a11y/approvals.json with the rebuilt pages. All test status

Package

Consumers link one stylesheet, css/classic/index.css, which includes every element. The files below are where this element is defined.

LanguageSelector package
Source css/classic/components/language-selector.css
Specimens also use Box · Card · Chip · Icon · Menu · Table · Text · Toolbar
Sprites sprites/icons.svg
React Not yet available: the React binding has not started.

Latest updates

LanguageSelector latest updates
Date Version Breaking Description
2026-10-20 0.1 No LanguageSelector (C-52), UI only, modeled on the USWDS Language selector: a Button naming the current language in that language (__current[lang], after a visually hidden "Language:") opens a C-07 Menu of menuitemradio languages, each its own name with lang (and dir="rtl" for Arabic) glossed in the page's language, the current one checked; a two-language app uses __toggle, a link in the other language with lang and hreflang. Keyboard is the Menu's. Adds the Tabler language glyph to the sprite (components/language-selector.css)

All release notes