Domphy

Typography

Type scale

Domphy theme includes an 8-step type scale (size 0–7, matching @domphy/theme's size system):

StepDefaultUse case
011pxCaptions, legal text, badges
112pxHelper text, timestamps
214pxBody text (small)
316pxBody text (default)
418pxLead text, secondary headings
520pxH3, section headers
624pxH2, card titles
732pxH1, page titles

Access via themeSize:

import { themeSize } from "@domphy/theme"

const Caption = {
  span: "Posted 3 days ago",
  style: { fontSize: themeSize(1) },   // "12px" (or rem equivalent)
}

Font tokens

Override the theme's font stack at any scope:

import { themeApply } from "@domphy/theme"

// Global font setup (in app root)
document.documentElement.style.setProperty("--font-sans", "'Inter', system-ui, sans-serif")
document.documentElement.style.setProperty("--font-mono", "'JetBrains Mono', monospace")

Or via theme configuration:

import { themeApply } from "@domphy/theme"

themeApply(document.documentElement, {
  fontSans: "'Inter', system-ui, sans-serif",
  fontMono: "'JetBrains Mono', monospace",
  fontSerif: "'Lora', Georgia, serif",
})

In elements, reference font tokens:

const MonoText = {
  code: "const x = 1",
  style: { fontFamily: "var(--font-mono)" },
}

Typography patch

Apply the full typography treatment (size + weight + line-height + color) with the typography patch:

import { typography } from "@domphy/ui"

const Article = {
  article: [
    { h1: "Title", $: [typography({ size: 7, weight: "bold" })] },
    { p: "Body text.", $: [typography({ size: 3 })] },
    { small: "Caption", $: [typography({ size: 1, tone: "shift-3" })] },
  ],
}

Responsive text

Scale text size based on viewport width using CSS clamp():

const Hero = {
  h1: "Welcome",
  style: {
    // Scales from 24px at 320px viewport to 48px at 1280px
    fontSize: "clamp(1.5rem, 3vw + 0.5rem, 3rem)",
    lineHeight: "1.1",
  },
}

Or define size steps per breakpoint with CSS media queries in a <style> block:

h1 { font-size: 1.75rem; }
@media (min-width: 768px) { h1 { font-size: 2.25rem; } }
@media (min-width: 1280px) { h1 { font-size: 3rem; } }

Line height

Line height affects readability. Theme defaults:

UseLine height
Headings (tight)1.1–1.2
Body text1.5–1.6
Dense UI (captions, labels)1.25
Code1.75
const Body = {
  p: "Readable paragraph text.",
  style: {
    fontSize: themeSize(3),
    lineHeight: "1.6",
  },
}

Font weight

const weights = {
  thin:       100,
  extralight: 200,
  light:      300,
  regular:    400,   // body
  medium:     500,   // labels, buttons
  semibold:   600,   // subheadings
  bold:       700,   // headings
  extrabold:  800,
  black:      900,
}

const Heading = {
  h2: "Section",
  style: { fontWeight: weights.semibold },
}

Prose / content regions

For user-generated or markdown-rendered content, apply the paragraph patch to set consistent spacing and line-height across all text elements:

import { paragraph } from "@domphy/ui"

const Content = {
  article: markdownBody,   // rendered markdown elements
  $: [paragraph()],        // applies body typography to all text children
}

Vertical rhythm

Consistent spacing between text blocks using themeSpacing:

import { themeSpacing } from "@domphy/theme"

const TextBlock = {
  div: [
    { h2: "Section Title" },
    { p: "First paragraph." },
    { p: "Second paragraph." },
  ],
  style: {
    "& h2": { marginBottom: themeSpacing(2) },
    "& p + p": { marginTop: themeSpacing(3) },
  },
}

Letter spacing

Fine-tune tracking for display text or all-caps labels:

const Eyebrow = {
  span: "CATEGORY",
  style: {
    fontSize: themeSize(0),
    fontWeight: 600,
    letterSpacing: "0.08em",
    textTransform: "uppercase",
  },
}

Font loading

Preload critical fonts in your HTML head for zero-layout-shift:

// In press.config.ts or app head config
const head = [
  `<link rel="preconnect" href="https://fonts.googleapis.com">`,
  `<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>`,
  `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap">`,
]

Or self-host with @font-face:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}

Pairing with tone

Text color inherits from the tone system — use themeColor for accessible text:

import { themeColor } from "@domphy/theme"

const Muted = {
  span: "Secondary info",
  style: {
    color: themeColor("neutral", 6),   // tone-shifted neutral text
    fontSize: themeSize(2),
  },
}

See the Tone guide for the full color-role model.