Code
<script lang="ts">
import { LocaleButton, type LocaleButtonLocale } from 'sv5ui-plus'
import { setLocale, toLocale } from '$lib/paraglide/runtime'
const locales: LocaleButtonLocale[] = [
{ code: 'en', label: 'English', shortLabel: 'EN' },
{ code: 'th', label: 'Thai', shortLabel: 'TH' }
]
let locale = 'en'
</script>
<LocaleButton
{locales}
{locale}
onLocaleChange={(nextLocale) => {
locale = nextLocale
const target = toLocale(nextLocale)
if (target) {
return setLocale(target, { reload: false })
}
}}
/>
LocaleButton
A language switcher button designed to work nicely with Paraglide. Use onLocaleChange for setLocale() flows while keeping the
current path unchanged.
Basic Usage
Choose Your Strategy
LocaleButton is only the UI layer.
Your app decides how locale changes are applied.
Callback Strategy
RecommendedUse onLocaleChange when your app controls locale changes in code. This works well with Paraglide cookie-based setups and custom i18n stores.
- Keeps the current pathname unchanged
- Works with setLocale(..., { reload: false })
- Best default for consumer apps
Href Strategy
OptionalUse getLocaleHref when your app intentionally exposes locale-specific URLs such as /th/docs or /en/docs.
- Generates per-locale links
- Useful for URL-prefix routing
- Navigation happens through hrefs instead of imperative state
Custom I18n
FlexibleYou can use LocaleButton without Paraglide at all. Pass your own locale state, persistence, and translation runtime.
- No hard dependency on Paraglide
- Works with stores, cookies, or API-backed preferences
- Good for non-SvelteKit or mixed stacks
Paraglide with setLocale
Use the selection callback when your app already manages locale changes in code.
Paraglide setLocale()
<script lang="ts">
import { LocaleButton, type LocaleButtonLocale } from 'sv5ui-plus'
import { setLocale, toLocale } from '$lib/paraglide/runtime'
const locales: LocaleButtonLocale[] = [
{ code: 'en', label: 'English', shortLabel: 'EN' },
{ code: 'th', label: 'Thai', shortLabel: 'TH' }
]
let locale = 'en'
</script>
<LocaleButton
{locale}
{locales}
onLocaleChange={(nextLocale) => {
locale = nextLocale
const target = toLocale(nextLocale)
if (target) {
return setLocale(target)
}
}}
/>
Use In Consumer Apps
LocaleButton is exported from
the sv5ui-plus package and can be used
in any app that installs this library.
The component does not depend on Paraglide internally. Your app provides locale, locales, and the locale-change
logic through onLocaleChange or getLocaleHref.
Consumer app example
<script lang="ts">
import { LocaleButton, type LocaleButtonLocale } from 'sv5ui-plus'
import { setLocale, toLocale } from '$lib/paraglide/runtime'
const locales: LocaleButtonLocale[] = [
{ code: 'en', label: 'English', shortLabel: 'EN' },
{ code: 'th', label: 'Thai', shortLabel: 'TH' }
]
let locale = 'en'
</script>
<LocaleButton
{locales}
{locale}
onLocaleChange={(nextLocale) => {
locale = nextLocale
const target = toLocale(nextLocale)
if (target) {
return setLocale(target, { reload: false })
}
}}
/>
Keep The Same Path
With cookie-based Paraglide strategy, you can switch locale without adding /th or other locale prefixes to the
URL.
Paraglide without locale prefix
<script lang="ts">
import { LocaleButton, type LocaleButtonLocale } from 'sv5ui-plus'
import { setLocale, toLocale } from '$lib/paraglide/runtime'
const locales: LocaleButtonLocale[] = [
{ code: 'en', label: 'English', shortLabel: 'EN' },
{ code: 'th', label: 'Thai', shortLabel: 'TH' }
]
let locale = 'en'
</script>
<LocaleButton
{locale}
{locales}
onLocaleChange={(nextLocale) => {
locale = nextLocale
const target = toLocale(nextLocale)
if (target) {
return setLocale(target, { reload: false })
}
}}
/>
Use Locale Prefix URLs
If your product intentionally uses locale-prefixed routes such as /th/docs, provide getLocaleHref. This keeps
navigation declarative and lets the button render locale-specific links.
Href strategy with localizeHref()
<script lang="ts">
import { LocaleButton, type LocaleButtonLocale } from 'sv5ui-plus'
import { localizeHref } from '$lib/paraglide/runtime'
const locales: LocaleButtonLocale[] = [
{ code: 'en', label: 'English', shortLabel: 'EN' },
{ code: 'th', label: 'Thai', shortLabel: 'TH' }
]
let locale = 'en'
const pathname = '/docs/components/locale-button'
</script>
<LocaleButton
{locales}
{locale}
getLocaleHref={(nextLocale) => localizeHref(pathname, { locale: nextLocale })}
/>
Use Without Paraglide
The component works with any locale source of truth. You can connect it to a Svelte store, cookies, localStorage, an API-backed user preference, or another i18n runtime.
Custom i18n integration
<script lang="ts">
import { LocaleButton, type LocaleButtonLocale } from 'sv5ui-plus'
const locales: LocaleButtonLocale[] = [
{ code: 'en', label: 'English', shortLabel: 'EN' },
{ code: 'th', label: 'Thai', shortLabel: 'TH' }
]
let locale = 'en'
function applyLocale(nextLocale: string) {
locale = nextLocale
localStorage.setItem('preferred-locale', nextLocale)
}
</script>
<LocaleButton
{locales}
{locale}
onLocaleChange={(nextLocale) => {
applyLocale(nextLocale)
}}
/>
Locale Item Shape
Each locale entry is just data. Start with code and label, then add optional fields
only when your app needs them.
LocaleButtonLocale[]
import type { LocaleButtonLocale } from 'sv5ui-plus'
const locales: LocaleButtonLocale[] = [
{
code: 'en',
label: 'English',
shortLabel: 'EN',
description: 'Default content language'
},
{
code: 'th',
label: 'Thai',
shortLabel: 'TH',
description: 'Thai translation',
href: '/th/docs',
hreflang: 'th'
}
]
| Field | Required | Purpose |
|---|---|---|
| code | Yes | The locale identifier used by your i18n layer, such as en or th. |
| label | Yes | The full label rendered in the dropdown menu. |
| shortLabel | No | Compact text for the trigger or badge, such as EN or TH. |
| description | No | Secondary helper text shown inside the menu. |
| href | No | A precomputed locale-specific link if your app uses href navigation. |
| hreflang | No | Optional hreflang value forwarded to anchor items. |
| disabled | No | Disables a specific locale item. |
Integration Checklist
- Use onLocaleChange when you do not want locale prefixes in the URL.
- Use getLocaleHref only when your routing strategy intentionally includes locale-specific paths.
- Pass locale from your own source of truth so the trigger always reflects the current language.
- Provide shortLabel values when you want compact trigger text such as EN, TH, or JA.
- Use the children snippet when your product needs a fully custom trigger design.
Variants
Sizes
Control trigger button and dropdown menu item scaling from xs to xl. Font sizes, item
padding, badge indicators, and icons scale proportionally.
Custom Trigger
Use the children snippet to fully control
the trigger content while keeping the dropdown behavior.
Custom Menu Items
Use the item snippet to completely redesign
how each language row looks inside the dropdown.
Custom Menu Layout
If you need to break out of the standard vertical list, use the menu snippet to build an entirely
custom dropdown grid or layout.
Flag Icons Design
Here is a highly requested design: a circular flag trigger that reveals a dropdown of
languages with flags. This uses both the children and item snippets.
Fit Content
Use the fit prop to shrink the dropdown
menu width to fit its content (`w-fit min-w-0`) instead of using the default minimum width.
Positioning & Alignment
Control the dropdown popover position using side (`bottom`, `top`, `left`, `right`) and align (`start`, `center`, `end`).