Passer au contenu principal

LanguageSwitcher

Implemented

EN/FR bilingual toggle with instant language switch — inline EN | FR pair (header default) or compact single button showing the target locale (ADR-038: fab retired). Controlled and stateless: the consumer owns URL-segment navigation and the document language.

Categorymolecules
Sourcecomponents/molecules/languageswitcher/LanguageSwitcher.tsx
AI HintEN/FR locale switcher for headers and nav. inline variant renders an aria-current group of EN | FR buttons; compact renders a single button showing the TARGET locale. Controlled and stateless — the consumer owns the URL locale segment AND document.documentElement.lang. Prefer over the LanguageToggle atom (BCP 47 casing, group semantics).

EN/FR bilingual toggle with instant language switch. Two variants: inline (header, default) and compact (single-button); the fab variant was retired in ADR-038 (2026-09-17). D-HOME-P4b 2026-08-11 (test updated for new API).

LanguageSwitcher

Family 7 — Commerce Molecules

Bilingual switch with two visual variants. Inline shows EN | FR pair (default for header). Compact shows single button with the OTHER locale. All variants are WCAG 2.5.5 compliant (44x44px tap target). Controlled and stateless — the consumer owns URL-segment navigation and document.documentElement.lang. The fab variant was retired in ADR-038 (2026-09-17); mobile language switching is owned by the MobileNav drawer.

Inline (default, EN active)

Inline (FR active — aria-current flips)

Compact

Controlled (onLocaleChange fires)

Controlled — click a button: onLocaleChange fires, aria-current moves (active: en).

Usage

import { LanguageSwitcher } from '@epasslive/design-system'

// Header (desktop)
<LanguageSwitcher
  currentLocale={locale}
  onLocaleChange={switchLocale}
  groupLabel={t('switchLanguage')}
/>

// Compact (single button showing the other locale)
<LanguageSwitcher
  currentLocale={locale}
  onLocaleChange={switchLocale}
  variant="compact"
/>

Integration — what the consumer owns

The molecule is display/interaction only. A correct integration (1) navigates the URL locale segment on onLocaleChange (e.g. router.replace(pathname, { locale: next })) and (2) sets document.documentElement.lang. Note: the document-language half is currently broken app-wide (every /fr route serves <html lang="en">) — the app-level fix is tracked separately. Persistence (URL/cookie) is also consumer-side; the molecule keeps no state. The built-in per-button strings ("switch to", ", current") are English-only — localize groupLabel per page locale.

Atom vs molecule

Prefer this molecule for header/nav locale switching: aria-current group semantics and BCP 47 casing ("en" | "fr"). The LanguageToggle atom is a minimal single-token toggle (aria-pressed, uppercase 'FR' | 'EN') — its compact overlap with this molecule is a pending consolidation ADR. New integrations should use the molecule.

D-HOME-P4b changelog (2026-08-11)

  • Updated test name: "DS-CORR-07-03: LanguageSwitcher active locale uses bg-ep-btn-primary (AA contrast)"
  • Variant contract history: D-HOME-P4b set "inline" | "compact" | "fab"; ADR-038 (2026-09-17) retired "fab" — the union is now "inline" | "compact"

Accessibility

Native buttons with aria-label describing the language switch action. Active button has aria-current="true". 44x44px min tap target via min-h-[var(--ep-tap-min)] + min-w-[var(--ep-tap-min)]. Each button carries lang={opt.locale} (WCAG 3.1.2).

Props

Prop
Type
Default
Description
currentLocale*
'en' | 'fr'
—

Currently active locale. The matching button gets aria-current="true".

onLocaleChange
(locale: LanguageSwitcherLocale) => void
—

Called with the next locale when the user activates a button. Omit for display-only rendering.

options
LanguageSwitcherOption[]
—

Override the default EN/FR options.

variant
'inline' | 'compact'
inline

Visual variant — inline (default), compact (single button); the fab variant was retired in ADR-038.

groupLabel
string
—

Accessible label for the outer group (rendered when variant is inline).

className
string
—

Additional classes appended to the outermost element.

data-testid
string
—

Forwarded to the outer element.

Used By

  • storefront/src/components/layout/SiteHeader.tsx — inline (desktop, hidden below md)
  • storefront/src/components/layout/MobileNavDrawer.tsx — inline
  • storefront/src/components/docs/LanguageSwitcher.tsx — docs-site topbar wrapper (inline)

Props

Preview

LanguageSwitcher

Prop
Type
Required
Default
Description
currentLocale
'en' | 'fr'
Required
—

Currently active locale. The matching button gets aria-current="true".

onLocaleChange
(locale: 'en' | 'fr') => void
Optional
—

Called with the next locale when the user activates a button. Omit for a display-only rendering.

options
LanguageSwitcherOption[]
Optional
EN/FR defaults

Override the default EN/FR options ({ locale, shortLabel, nativeName, englishName } per entry; both locales must be present).

variant
"inline" | "compact"
Optional
'inline'

Visual variant: inline — text-only EN | FR pair (header use); compact — single button showing the other locale. ADR-038 retired the former fab value (mobile floating action button).

groupLabel
string
Optional
'Language switcher'

Accessible label for the outer group (rendered when variant is inline). Localize per page locale.

className
string
Optional
''

Extra classes appended to the outermost element.

data-testid
string
Optional
—

Forwarded to the outer element (data-* / id).

Quick use:<LanguageSwitcher />

Accessibility

ARIA rolegroup

ARIA

1 rule

WCAG 1.3.1

Current language must be announced (aria-current='true')

Type

1 rule

BCP 47

Locale is restricted to the supported set ('en' | 'fr'); extra locales require extending the type

validation

1 rule

W3C i18n

Native name should accompany English name

Usage

Import

tsxSnippet
import { LanguageSwitcher } from "@epasslive/design-system"

Example 1

tsxSnippet
<LanguageSwitcher currentLocale="en" />

Example 2

tsxSnippet
<LanguageSwitcher currentLocale={locale} variant="compact" onLocaleChange={switchLocale} />

Anti-patterns

— Do not hardcode data in molecules

— Avoid complex business logic in molecules

Design System v4.1.0 | ePassLive