Recipe: Cross-file design tokens
Define tokens in one file, consume them anywhere.
1. Declare tokens
// theme/tokens.ts
import { tl } from "traceless-style";
export const tokens = tl.defineTokens({
brand: {
primary: "#3b82f6",
secondary: "#10b981",
danger: "#dc2626",
},
text: {
default: "#0f172a",
muted: "#64748b",
inverse: "#f8fafc",
},
surface: {
default: "#ffffff",
muted: "#f1f5f9",
border: "#e2e8f0",
},
spacing: {
xs: "0.25rem", sm: "0.5rem", md: "1rem", lg: "2rem", xl: "4rem",
},
radius: { sm: "4px", md: "8px", lg: "16px", round: "999px" },
shadow: {
sm: "0 1px 3px rgba(0,0,0,0.1)",
md: "0 4px 12px rgba(0,0,0,0.1)",
lg: "0 10px 30px rgba(0,0,0,0.15)",
},
font: {
sans: "system-ui, -apple-system, sans-serif",
mono: "ui-monospace, SFMono-Regular, monospace",
},
});
export const dark = tl.createTheme("dark", {
brand: { primary: "#60a5fa" },
text: { default: "#f8fafc", muted: "#94a3b8", inverse: "#0f172a" },
surface: { default: "#0f172a", muted: "#1e293b", border: "#334155" },
});
2. Apply the dark theme at the root
// app/layout.tsx
import { TracelessRoot } from "traceless-style/dark";
import { dark } from "../theme/tokens";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head><TracelessRoot /></head>
{/* The body always has the dark class — TracelessRoot toggles `.dark` on <html>. */}
<body className={dark}>{children}</body>
</html>
);
}
3. Consume tokens
Member access:
// components/Card.tsx
import { tl } from "traceless-style";
import { tokens } from "../theme/tokens";
const $ = tl.create({
card: {
background: tokens.surface.default,
color: tokens.text.default,
border: `1px solid ${"" /* see below */}`, // ← can't compose
borderColor: tokens.surface.border,
padding: tokens.spacing.md,
borderRadius: tokens.radius.md,
boxShadow: tokens.shadow.sm,
fontFamily: tokens.font.sans,
},
});
Note: traceless-style's strict literal-only AST parser doesn't allow template literals, so you can't compose strings (e.g.
`1px solid ${tokens.x}`). Use a separateborderColor: tokens.xdeclaration.
tl.cssVar (no import needed):
tl.create({
card: {
background: tl.cssVar("surface-default"),
color: tl.cssVar("text-default"),
padding: tl.cssVar("spacing-md"),
},
});
4. Type-safe token names
import type { TokenKeyOf } from "traceless-style";
import { tokens } from "../theme/tokens";
type AppToken = TokenKeyOf<typeof tokens>;
// = "brand-primary" | "brand-secondary" | "brand-danger"
// | "text-default" | "text-muted" | "text-inverse"
// | "surface-default" | "surface-muted" | "surface-border"
// | "spacing-xs" | "spacing-sm" | … | "shadow-lg"
// | "font-sans" | "font-mono"
tl.cssVar<AppToken>("brand-primary"); // ✓
tl.cssVar<AppToken>("brand-typo"); // ✗ TS error at compile time
5. Debug if a token isn't expanding
TRACELESS_STYLE_DEBUG_RESOLVE=1 npx traceless-style
Prints the per-file token export registry. Common causes:
- Missing
exportkeyword on thedefineTokenscall. - Path-alias misconfigured in
tsconfig.json compilerOptions.paths. - Typo in the leaf path passed to
tl.cssVar.
See also
See also
Learn
Tokens & themesDesign tokens are named, themable values — a single source of truth for colors, spacing, type scales, etc. They compile to CSS custom proper
Reference
Cross-file resolutionTokens defined in one file work in another. This page documents every supported import form and the resolver rules.
API
tl.defineTokensDeclare design tokens. Compiles to CSS custom properties at :root and returns a typed nested object whose leaves are var(--tl-<hash>) refere