Locale Toggle

A controlled language button or selector without routing or persistence assumptions.

Loading example…

Installation

bunx --bun shadcn@latest add @sui/locale-toggle

Install with the shadcn CLI or use the shared @workspace/ui package. Follow the installation guide to configure the registry, load styles, and choose import aliases.

Usage

import { LocaleToggle } from "@workspace/ui/components/locale-toggle";
import { useState } from "react";

const options = [
  { value: "en-US", label: "English" },
  { value: "zh-CN", label: "简体中文" },
];

export function Language() {
  const [value, setValue] = useState("en-US");
  return <LocaleToggle value={value} onValueChange={setValue} options={options} />;
}

Toggle and select modes

In auto mode, up to two distinct options use a button that cycles to the next language; more options use the shared Select. Set mode="toggle" or mode="select" to choose explicitly. A button with fewer than two distinct options is disabled. Duplicate option values are removed.

Loading example…

Integrating routing and content

onValueChange reports a locale value after the indicator reaches its new shape. Your application updates content, router state, and any persisted preference. The control locks immediately and keeps aria-busy during the morph and any promise returned by the callback. Repeated clicks share the pending request. Reduced motion or a hidden page completes the shape immediately. Rejection releases the pending state and restores the controlled locale indicator; the application callback handles error reporting. Unmounting before the animation ends cancels the callback. The selected locale remains controlled by value. No router, translation provider, or storage API is required by the component. The examples keep the selection local and do not navigate the documentation.

For this documentation’s language routes, switching preserves the page path, query, and hash. That behavior belongs to the application’s route integration, not to the shared toggle component.

Option indicators and labels

Every option has a full locale value and readable label. The ghost button has a tooltip and a 16px SVG indicator with 2px strokes. ZH and EN use compact stroke lettering with a snappy spring path morph. Common language prefixes have built-in indicators; reduced motion swaps the shape directly. indicatorPath overrides its SVG path, while unknown prefixes use the generic language icon. Translate the control label and use readable option names. Native button props include disabled, ref, and render.

API reference

PropTypeDefault / behavior
valuestringRequired selected locale.
onValueChange(value: string) => void | Promise<void>Required selection callback.
optionsreadonly LocaleOption[]Required options: value, label, optional indicatorPath.
mode"auto" | "toggle" | "select""auto".
labelstring"Change language".
glassbooleanfalse.

The module exports LocaleToggleProps and LocaleOption. The multi-language selector uses the Base UI Select API.