shadcn.io is not affiliated with official shadcn/ui
Language Switch Dialog Block for React
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.
Installation
Overview
Let readers pick the language of a site and see it change, with this language dialog for React with Base UI. It opens from the Site language page of Babelpage, a multilingual docs site: the header holds an outline Button with a globe and the name of the language the page reads in now, and the landing page is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The dialog is a Radio Group of eight languages, each named in its own script with the English name beside it, a thin Progress bar and "92% translated" so a reader knows what they will get. Apply, the only Shine Button, closes the dialog and the page behind it changes: its headline, sentence and button are typed in all eight languages, and Arabic turns the whole page right-to-left. For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog, with the same list and the same choice. For docs sites, help centres, storefronts and any app with a language menu.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The header button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same LanguageFields component and share the block's state, so a language chosen in the copy is chosen in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
What changes when I press Apply?
The landing page drawn behind the dialog. Its headline, sentence and button are typed in all eight languages in LANGUAGES, the language chip in its top bar and the header button show the new name, and a polite status message says what changed. Arabic also sets dir="rtl" on the drawn page, so the rows mirror and the text reads from the right; every other language sets its own lang. Cancel, Escape and the close button leave the page as it was and reset the choice.
What stays local, and how do I wire it for real?
Everything. The translations, the coverage percentages and the choice live in the file and in the block's state; no locale is set on your browser, no cookie is written and no request goes out. In your app send the chosen id to your router or i18n library in apply (a locale prefix on the URL, or a stored preference), and compute the percentages from your catalogue of strings: translated divided by total, per language. Swap the typed headline for your own message files.
How is coverage shown, and what does it mean?
Each row prints "74% translated" and draws the same share as a thin bar. The numbers are typed here as the share of the site's strings that have a translation; a language below 100% shows the rest in the original. The bar is decoration and hidden from assistive technology, because the percentage is already in the row's text.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus is trapped while it is open, and Escape, Cancel and the close button return focus to the header button. The languages are a radio group: the arrow keys move and choose in one step, Tab leaves the group, and each name carries its own lang so a screen reader pronounces it in that language. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The copy shown on load moves no focus; Escape inside it, Cancel and its close button close it and put focus on the header button.
How does it look on a phone?
The copy shown on load docks to the foot of the page as a bottom sheet with Apply pinned at the bottom and the eight languages scrolling above it. The real dialog keeps the Dialog's own phone layout: a sheet stuck to the bottom of the screen. The drawn page keeps its headline, sentence and button and drops the menu bars.
Related
- 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
Language and Region Settings
Appearance and localeA language and region settings panel: two selects over three cells that show what they do, a sort order made by the language's collation, a month marked with the region's first weekday, and units with a worked example.
- Pro
Time Zone Picker Dialog
Time and schedulingA preferences page with its time zone dialog shown open: a search over 14 zones in four regions, each row with its city, UTC offset and the time there at one typed moment, a button that reads this device's zone on a press, and the chosen zone printed back on the page.
- Pro
A time tracker's Today page with a preferences sheet shown open where each setting shows its effect: a theme choice over a preview card, a text size and a reduce-motion switch acting on a sample, a default view and two behaviour switches.
- Pro
Select Template Dialog
Pickers and searchA documents app's new-document dialog shown open: six icon tiles in two columns that move with the arrow keys and jump on a typed letter, Popular and New badges, a Create button that names the choice, and the new file landing on the home.
- Pro
Add Card Dialog
Payments and plansA transit wallet's payment methods page with its add-card dialog shown open: a card drawn in greys that fills in as you type, a number that groups itself and names its network, checks on the number, expiry and code, and an Add card button that keeps only the last four digits.