- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Code Block
- Collapsible
- Combobox
- Command
- Context Menu
- Copy Button
- Data Table
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Form
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- Menubar
- Native Select
- Navigation Menu
- Page Header
- Pagination
- Panel
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Section Header
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Stat
- Stat Card
- Switch
- Table
- Tabs
- Textarea
- Theme Toggle
- Toggle
- Toggle Group
- Tooltip
CJK
The .label utility adapts automatically for Chinese, Japanese, and Korean via CSS :lang() — no component changes required.
Why CJK needs different label styles
Swiss UI uses uppercase Geist Mono with wide letter-spacing for the `.label` utility — on labels, buttons, badges, table headers, and navigation. That pattern works for Latin scripts but breaks down for CJK:
- Uppercase has no effect — Chinese, Japanese, and Korean have no case distinction.
- Wide tracking spreads glyphs apart — letter-spacing applies per character, making CJK text look broken and sparse.
- Mono fonts lack CJK glyphs — Geist Mono loads Latin only; without Noto Sans, CJK falls back to inconsistent OS fonts.
The fix is automatic: set lang on an ancestor and `.label` styles switch to sans-serif, medium weight, and normal tracking. Same components, same classes — only the lang attribute changes:
How it works
`.label` styles are driven by CSS custom properties. Latin locales use the default values; CJK locales override them via :lang():
| Property | Latin | CJK |
|---|---|---|
| font-family | Geist Mono | Noto Sans (locale) |
| text-transform | uppercase | none |
| letter-spacing | 0.08em | normal |
| font-weight | 500 | 500 |
Supported lang values: ja, ko, zh, zh-CN, zh-TW, zh-HK.
/* globals.css — included with the swiss style item */
:root {
--label-font: var(--font-mono);
--label-transform: uppercase;
--label-tracking: 0.08em;
--label-weight: 500;
}
:lang(ja) {
--label-font: var(--font-sans-ja);
--label-transform: none;
--label-tracking: normal;
font-family: var(--font-sans-ja), var(--font-sans), sans-serif;
}
:lang(ko) {
--label-font: var(--font-sans-ko);
font-family: var(--font-sans-ko), var(--font-sans), sans-serif;
/* ...same label resets */
}Setup
If you installed the swiss style item, the label tokens, :lang() overrides, and four Noto Sans font items (JP, KR, SC, TC) are installed together. Geist Sans only covers Latin — without Noto, CJK text falls back to OS system fonts with inconsistent weight across locales.
// app/layout.tsx — load CJK fonts via next/font/google
import {
Noto_Sans_JP,
Noto_Sans_KR,
Noto_Sans_SC,
Noto_Sans_TC,
} from "next/font/google"
const notoSansJP = Noto_Sans_JP({
variable: "--font-sans-ja",
weight: ["400", "500", "600"],
preload: false,
})
// ... KR, SC, TC likewise
<html className={`${notoSansJP.variable} ${notoSansKR.variable} ...`}>Locale → font mapping:
ja→ Noto Sans JP (--font-sans-ja)ko→ Noto Sans KR (--font-sans-ko)zh,zh-CN→ Noto Sans SC (--font-sans-sc)zh-TW,zh-HK→ Noto Sans TC (--font-sans-tc)
The .label utility (0.75rem / 12px) is used by UI components and custom markup alike. It reads the same --label-* CSS variables.
@layer utilities {
.label {
font-family: var(--label-font);
font-size: 0.75rem;
line-height: 1;
font-weight: var(--label-weight);
text-transform: var(--label-transform);
letter-spacing: var(--label-tracking);
}
}Setting the lang attribute
Page-level — set lang on <html> so every `.label` on the page adapts:
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ko">
<body>{children}</body>
</html>
)
}Element-level — for mixed-language pages, wrap CJK content with a lang attribute on a container or individual element:
<div lang="ko">
<Label htmlFor="email">이메일</Label>
<Button type="submit">저장</Button>
</div>
{/* or on a single element */}
<span className="label" lang="ko">카테고리</span>Common mistake: if lang is not set (or stays en), CJK text will still receive uppercase styling and wide tracking. Always match lang to the content language.
Live component gallery
The same Swiss UI components with Korean, Japanese, and Simplified Chinese text. Each column is wrapped in a lang container — no className overrides.
| 이름 | 상태 | 날짜 |
|---|---|---|
| — | — | — |
| 名前 | 状態 | 日付 |
|---|---|---|
| — | — | — |
| 名称 | 状态 | 日期 |
|---|---|---|
| — | — | — |
Manual override (optional)
In most cases the automatic :lang() switch is sufficient. If you need to force body typography on a `.label` element, override with:
<Label className="font-sans font-normal tracking-normal normal-case">
Custom label
</Label>The Button link variant already uses sans-serif with normal case and tracking. Kbd shortcut hints (tracking-widest) are Latin-only and are not affected by CJK overrides.