Skip to content
Domphy

API

This page lists the public helpers exported by @domphy/theme.

Common Runtime Helpers

themeColor(object, tone?, color?)

Resolve a color CSS variable reference (var(--…)) from the current theme and tone context.

backgroundColor: (listener) => themeColor(listener, "inherit", "primary")
color: (listener) => themeColor(listener, "shift-9", "primary")

object accepts an ElementNode, a Listener, or null. Pass null to resolve against the light theme with no context.

Use this for text color, background color, outline color, and interaction states.

themeColorToken(object, tone?, color?)

Same signature as themeColor but returns the resolved token value (e.g. "#4a7ff4") instead of a var(--…) CSS reference. Use at design-time or when integrating with third-party APIs that require a concrete color string.

const hex = themeColorToken(null, "shift-9", "primary") // e.g. "#4a7ff4"

object may be null — resolves against the light theme with no node context.

themeSize(object, size?)

Resolve a font size from the nearest dataSize context. object must be an ElementNode or a Listener — unlike themeColor, it does not accept null.

fontSize: (listener) => themeSize(listener, "inherit")
fontSize: (listener) => themeSize(listener, "increase-1")

themeDensity(object)

Resolve the current density factor from the nearest dataDensity context. object accepts an ElementNode, a Listener, or null. Pass null to resolve against the default density with no context.

const d = themeDensity(listener)

paddingBlock: themeSpacing(d * 1)
paddingInline: themeSpacing(d * 3)

themeDensity() returns a number, not a CSS value.

themeSpacing(n)

Return a CSS calc(n/4 em) string. The result is wrapped in calc() to preserve composability.

gap: themeSpacing(3)
minWidth: themeSpacing(32)
height: themeSpacing(6)

themeFluidSpacing(min, max, viewportMin?, viewportMax?)

Return a CSS clamp() that scales between themeSpacing(min) and themeSpacing(max) across a viewport width range (default 320 px → 1280 px). Use for structural spacing — page padding, section gaps — that should grow with the viewport.

import { themeFluidSpacing } from "@domphy/theme"

padding: themeFluidSpacing(4, 16)    // 1em at 320px → 4em at 1280px
gap: themeFluidSpacing(4, 8)         // 1em at 320px → 2em at 1280px

Do not use fluid spacing for bounded-control padding (buttons, inputs) — use themeSpacing(themeDensity(l) * n) instead.

applySystemTheme(targetEl?, options?)

Detect the OS color-scheme preference, apply data-theme to targetEl (default: document.documentElement), and set up a listener for OS-level changes. Returns a cleanup function that removes the listener.

import { applySystemTheme } from "@domphy/theme"

// One-liner: reads localStorage first, falls back to OS preference
const cleanup = applySystemTheme()

// Custom target or storage key
const cleanup = applySystemTheme(document.getElementById("app")!, {
  storageKey: "my-theme",
})

Options:

OptionTypeDefaultDescription
persistbooleantrueSave resolved theme in localStorage
storageKeystring"dp-theme"localStorage key

Setup Helpers

themeApply(el?)

Inject the CSS for all registered themes into the DOM.

themeApply()
themeApply(styleTag)

themeCSS()

Return the CSS string for all registered themes. Mostly used for SSR.

const css = themeCSS()

setTheme(name, input)

Register or override a theme.

setTheme("brand", {
  colors: {
    primary: ["#fff", "..."],
  },
})

getTheme(name)

Return the full theme object.

const brand = getTheme("brand")

generateTheme(baseColors, options?)

Build a full PartialThemeInput from one base hex color per semantic role, using @domphy/palette's generateRamp for every family — see Theme Builder for a live demo and DESIGN.md for the math.

setTheme("brand", generateTheme({
  primary: "#4a7ff4",
  secondary: "#d8597d",
  neutral: "#8d8d8d",
}))

Each role's baseTones entry is picked automatically (nearest CIEDE2000 match to the input color). Roles you don't pass are simply absent from the result — setTheme() deep-merges the rest from whatever theme name already had (or light, if name is new).

Token Helpers

themeVars()

Return CSS variable references such as var(--primary-6) and var(--fontSize-2).

themeTokens(name)

Return the raw token object of a registered theme.

themeName(object)

Return the active theme name for the current node or listener.

Theme Shape

setTheme() accepts a partial ThemeInput.

type ThemeInput = {
  direction: "lighten" | "darken"
  colors: Record<string, string[]>
  baseTones: Record<string, number>
  fontSizes: string[]
  densities: number[]
  darkBias: number
  custom: Record<string, string | number>
}

For how tone and size resolution work, see Tone and Size.

Exported Types

TypeDescription
ThemeInputFull theme shape accepted by setTheme(). All fields are optional when passing a partial.
PartialThemeInputDeep-partial version of ThemeInput — what setTheme() actually accepts at runtime.
ThemeVarsObject of var(--…) CSS variable references returned by themeVars().
ThemeColorColorRole | (string & {}) — the 10 built-in role names rank first in editor autocomplete/hover, but any string still type-checks (custom themes may register their own role names via setTheme/generateTheme). This is intentionally NOT a strict union — see ColorRole below for the exhaustive list.
ColorRoleStrict union of the 10 built-in semantic role names: "neutral" | "primary" | "secondary" | "info" | "success" | "warning" | "attention" | "error" | "danger" | "highlight". Derived from COLOR_ROLES below.
ElementToneValid tone descriptor strings: "inherit", "base", "shift-N", "increase-N", "decrease-N", or a semantic alias ("surface", "hover", "border", "border-strong", "muted", "text") — see Semantic Aliases.
ElementTonesRuntime array of all valid tone strings (exported as a value for validation tooling).
ElementSizeValid size descriptor strings: "inherit", "increase-N", "decrease-N" (N 0–7).
ElementDensityValid density descriptor strings: "inherit", "increase-N", "decrease-N" (N 0–4).

COLOR_ROLES — runtime readonly array of the same 10 names (ColorRole's source of truth: type ColorRole = (typeof COLOR_ROLES)[number]). Use this instead of hand-listing the 10 roles when you need them as a real iterable (e.g. rendering one control per role).