Search documentation

Search components and pages

CJK

The .label utility adapts automatically for Chinese, Japanese, and Korean via CSS :lang() — no component changes required.

01

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:

Latin (lang=en)Active
CJK (lang=ko)활성
02

How it works

`.label` styles are driven by CSS custom properties. Latin locales use the default values; CJK locales override them via :lang():

PropertyLatinCJK
font-familyGeist MonoNoto Sans (locale)
text-transformuppercasenone
letter-spacing0.08emnormal
font-weight500500

Supported lang values: ja, ko, zh, zh-CN, zh-TW, zh-HK.

css
/* 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 */
}
03

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.

tsx
// 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.

css
@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);
  }
}
04

Setting the lang attribute

Page-level — set lang on <html> so every `.label` on the page adapts:

tsx
// 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:

tsx
<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.

05

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.

Korean
신규
개요
이름상태날짜
탐색
Japanese
新規
概要
名前状態日付
ナビ
Chinese
新建
概览
名称状态日期
导航
06

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:

tsx
<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.