tailwind2-2 Exercise 3: Scales as Tokens, and a Token Report ============================================================= Setup: a folder with Tailwind installed and Node. Create these three files. --- tok.css --- @import "tailwindcss" source(none); @source "./tpl.html"; @theme { --color-*: initial; --color-ink: oklch(0.25 0.02 260); --color-brand: oklch(0.55 0.2 260); --spacing: 0.5rem; --text-body: 1rem; --text-body--line-height: 1.6; --text-display: 2.5rem; --text-display--line-height: 1.1; --text-display--font-weight: 700; --radius-card: 0.75rem; } --- tpl.html ---
--- tokens.mjs (lists the variables Tailwind wrote, grouped by name prefix) --- // usage: node tokens.mjs compiled.css import { readFileSync } from 'node:fs'; const css = readFileSync(process.argv[2], 'utf8'); const theme = css.match(/@layer theme \{\s*:root, :host \{([\s\S]*?)\n \}\n\}/)[1]; const vars = [...theme.matchAll(/^\s*(--[\w-]+):\s*([\s\S]*?);\s*$/gm)].map(m => [m[1], m[2].replace(/\s+/g, ' ')]); const groups = {}; for (const [name, value] of vars) { const m = name.match(/^--(color|text|radius|font|spacing|default)/); const g = m ? m[1] : 'other'; (groups[g] ||= []).push([name, value]); } for (const [g, list] of Object.entries(groups)) { console.log(`\n## ${g} (${list.length})`); for (const [n, v] of list) console.log(`| ${n.padEnd(28)} | ${v.slice(0, 48)}`); } --- run --- npx @tailwindcss/cli -i tok.css -o tok.out.css node tokens.mjs tok.out.css for k in text-ink bg-brand p-4 rounded-card text-body text-display bg-red-500 text-white rounded-lg; do grep -q "^ \.$k " tok.out.css && echo "$k: rule" || echo "$k: NO RULE" done grep -A3 "^ \.p-4 " tok.out.css Output: ## font (2) | --font-sans | -apple-system, BlinkMacSystemFont, "Segoe UI", R | --font-mono | ui-monospace, SFMono-Regular, Menlo, Monaco, Con ## spacing (1) | --spacing | 0.5rem ## radius (2) | --radius-lg | 0.5rem | --radius-card | 0.75rem ## default (2) | --default-font-family | var(--font-sans) | --default-mono-font-family | var(--font-mono) ## color (2) | --color-ink | oklch(0.25 0.02 260) | --color-brand | oklch(0.55 0.2 260) ## text (5) | --text-body | 1rem | --text-body--line-height | 1.6 | --text-display | 2.5rem | --text-display--line-height | 1.1 | --text-display--font-weight | 700 text-ink: rule bg-brand: rule p-4: rule rounded-card: rule text-body: rule text-display: rule bg-red-500: NO RULE text-white: NO RULE rounded-lg: rule and for the p-4 rule: .p-4 { padding: calc(var(--spacing) * 4); } WHY THIS WORKS AS AN ANSWER --------------------------- --color-*: initial removes every colour in the default palette, then the two colours you define are the only ones: the report lists two colour variables, and bg-red-500 has no rule. text-white has no rule either, because white is also a colour in that namespace; if you reset the palette you must define white, black and transparent yourself if you still use them. --spacing: 0.5rem changes the base unit, so p-4 is still calc(var(--spacing) * 4), now 2rem instead of 1rem, which is why all spacing, sizing and gap utilities move together from one line. A font-size token takes optional companions in the same namespace: --text-body--line-height and --text-display--line-height / --font-weight, which the text-body and text-display utilities pick up (the rule for text-display reads all three). A new radius token creates rounded-card, while rounded-lg still works because only --radius-lg was left in the radius namespace (the page uses it). The report shows what is really in the file: the default fonts, one spacing base, the radius tokens and your own. A plain @theme token is only written when a class uses it, so the report is of what this page needs, not of everything defined.