LeCodesdocs

Fonts

Fonts are declarative: the compile-time font() macro installs a font and returns its family name — using a font is declaring it. There is nothing to load, await, or gate on; faces travel with the app (bundled locally or prefetched by the host before first paint) and text simply renders in them. System families need no installation: "serif", "sans-serif", "monospaced" work as fontFamily values out of the box.

At a glance

TypeScript
theme({ fontFamily: font("manrope") })          // app-wide default text font

UIScreen(
  UIText("Display").style({ fontFamily: font("unbounded"), fontSize: 32 }),
  UIText("Body text"),                          // theme default — Manrope
).open()                                       // no Promise.all, no gating — ever

font(id) — the registry

font("manrope") resolves against the curated font registry (~26 OFL families, Cyrillic-capable unless noted) and compiles to the family-name string "Manrope"; the faces it implies are registered automatically before your code runs.

TypeScript
font(id: string, opts?: { weights?: number[], italic?: boolean }): string
  • Installs the family's standard weights by default (usually 400/500/700). { weights: [400, 600] } narrows or extends the set — install the weights you actually use (fontWeight: 600 wants a 600 face; hosts substitute the nearest one otherwise).
  • { italic: true } adds italic faces alongside the upright ones (a compile error names the families/weights that ship no italics).
  • The argument must be a string literal — an unknown id is a compile error listing valid ones.

Registry ids by category:

category ids
sans-serif inter manrope golos-text onest rubik nunito montserrat ibm-plex-sans pt-sans jost exo-2
display unbounded russo-one oswald comfortaa space-grotesk (latin-only)
serif playfair-display lora pt-serif cormorant literata
monospace jetbrains-mono fira-code ibm-plex-mono
handwriting caveat pacifico

font("./path.ttf") — your own font files

A path-shaped argument installs a project font file. The compiler reads the file itself — the real family name from its name table, weight and italic from OS/2 — so there are no naming conventions to follow and no options to pass:

TypeScript
theme({ fontFamily: font("./fonts/Brand.ttf") })   // → "Brand" (from the file)
font("./fonts/Brand-Bold.ttf")                     // same family, adds the bold face

.ttf/.otf only (convert WOFF/WOFF2 exports); the path is relative to the calling file, like asset().

System fonts

Three generic families are plain fontFamily strings — no font(), nothing installed or fetched (calling font("serif") is a compile error pointing you here):

TypeScript
UIText("Quote").style({ fontFamily: "serif" })
UIText("SKU-10442").style({ fontFamily: "monospaced" })   // CSS's "monospace" also accepted

Each platform resolves them to its own native face (iOS serif is New York, Windows is Times New Roman, and so on) — use them when you want the platform's look, and a registry font when you want the same face everywhere. Design-board snapshots and lecodes render pin them to bundled concrete faces so headless output is deterministic: serif → PT Serif, monospaced → JetBrains Mono, sans-serif → Roboto (the default UI font).

How it loads (and why you never wait)

Declared faces are compile-known: local/standalone builds bundle them next to the app (they register synchronously at boot — no flash at all), and platform builds bake CDN URLs that the host prefetches in parallel with app startup, holding the first frame briefly so text appears in the right font from the start. If a face arrives late (bad network), text swaps in when it lands — that's the fallback, not the normal path.

Choosing the font per element

fontFamily is set per UIText (or via the app-wide theme({ fontFamily }) default) — don't rely on setting it on a container. Extract a shared Style<UIText> for repeated custom styling.

registerFont — runtime escape hatch

TypeScript
registerFont(fontFamily: string, url: string, options?: { weight?: number, style?: "normal" | "italic" }): Promise<void>

Only for URLs computed at runtime (a font picker, user-supplied fonts). One call per face; the promise resolves when the face is usable, but with font() covering registry and project files you almost never need this — and never need to await it.

See also