shadcn.io is not affiliated with official shadcn/ui
Language Switcher Command Menu Block for React
A language-learning app's language menu as a command menu shown open above the language button in a lesson page's foot: ten languages by their own names with lang and dir set, a completeness bar and percent, search in any script, and a lesson page whose labels flip.
Installation
Overview
Let people find their language in their own words with this language switcher command menu for React with Base UI. It opens from the Lessons page of Tonguefield, a language-learning app, whose header holds an outline field with its ⌘ K cap, and the page is drawn under a soft scrim inside a hairline frame with a plus mark on each corner: a lesson with a title, a goal and two buttons, over a foot whose language button the menu rises from. The menu is the catalog Command. Ten languages are rows, each with its own name in its own script, set with its lang and dir="rtl" for Hebrew and Arabic, its English name, a thin Progress bar and "92% translated". Typing in any script matches either name, with or without accents, so "espanol", "Español" and "日本" all find their language. Choosing one flips four labels on the drawn lesson page among typed translations and sets the page's lang and dir; the foot button names the language in its own script. There are no flags and no emoji. Nothing is saved. For preview the menu is drawn open in place when the page loads; the field, or Ctrl or ⌘ K while focus is in the block, opens the real command dialog with the same rows and query. For learning apps, documentation sites, stores and any product that speaks more than one language.
FAQ
Why is the menu already open, and what do I keep?
So you can see it without a click. On load the menu is the Command drawn inline above the drawn language button, in a plain shell that is not modal, so nothing is trapped, hidden or focused and the page around the preview keeps working. The header's field opens the real command dialog, modal, with its focus trap, Escape and focus return, and the inline copy stays closed until a reload. Both show the same Palette and share the block's state, so the language you chose and what you typed in the copy are in the real dialog. In your app keep the dialog and drop the copy: the "in-place" state, the scrim with its shell and the Escape and blur effects.
Why does each language show its own name?
Because someone who cannot read the interface's language can still find theirs: Deutsch, Español, 日本語, עברית, العربية. Each native name is set with its own lang, so screen readers pronounce it and browsers pick the right font, and Hebrew and Arabic also carry dir="rtl", so their letters sit in the right order inside a left-to-right row. The English name sits under it for everyone else.
How does the search match?
It reads the native name, the English name and the language code, with accents and case folded away, so "espanol" finds Español and "arab" finds the Arabic row. The matched letters are marked in whichever name matched. The foot counts the languages that match ("3 of 10 languages") and says it aloud a moment after typing stops. A search with no match says to try the English name or the language's own.
What changes on the page when I choose one?
Four labels on the drawn lesson page (the title, the goal and the two buttons) switch among typed translations, and the page's wrapper gets the language's lang and dir, so choosing Hebrew or Arabic mirrors the layout. The foot button shows the language's own name. The drawing is hidden from assistive technology, so the status line says what was set. The translations are typed, in this demo only; in your app they come from your message catalogs.
What stays local, and how do I wire it?
All of it. Nothing is saved, no locale cookie is set and no page reloads. The completeness figures are typed data; in your app they come from your translation tool. pick is where you would set the locale (a route, a cookie or a user setting), and the status line is the one polite live region.
Is it accessible from the keyboard?
Yes. Type to search, the arrow keys move, Enter chooses the highlighted language and Escape closes the menu and puts focus on the field; Ctrl or ⌘ K opens the dialog while focus is inside the block, and only then. The current language is ticked and says so for screen readers. The rows are options of a cmdk listbox; the block turns off its own fuzzy filter and lists the rows itself.
Related
- Pro
Language Switcher Navbar
Accounts and scopesA navbar whose language button opens a searchable list of twelve languages in their own scripts; choosing one rewrites the bar's links and action, and choosing Arabic flips the whole bar right to left.
- Pro
A docs site's settings page with its language dialog shown open: eight languages named in their own script, each with a translation coverage bar, and an Apply button that re-reads the landing page behind it, flipping it right-to-left for Arabic.
- Pro
A team intranet's profile page with its language and region dialog shown open: a Language tab with a searchable list of eight languages, a Region tab with country, first day of the week and clock, and a live preview that reformats a sample date, time, number and amount with Intl.
- Pro
Translation Coverage Command Menu
Inspect dataA localisation platform's string finder as a command menu shown open under a band of language chips with their coverage: keys with their text in the chosen language or the word Missing, a Missing only switch and a copy key button.
- 1234Pro
Account Switcher Command Menu
SwitchersAn agency billing portal's account switcher as a command menu shown open under the account chip: four accounts with initials, role and plan, a tick on the current one, the keys 1 to 4 to switch straight to an account, and the chip and status line that follow the choice.
- Pro
Navigation Command Menu
Pages and docsA bank back office's navigation menu shown open: 24 pages in three levels, each row the name over its whole path, a search that reads the path by the start of each word, and a tick on the page you are on.