Theme package
@airframeui/theme is the token pipeline. CSS is the spec. This package reads your --af-* overrides, checks them, and writes token JSON the rest of the toolchain can use.
Export to Figma is the main job. It is not the whole package. Inbound mapping (generate / lint) is here too. Git stays the source of truth.
Most apps never import the library. Override --af-* in CSS (Theming), then run the CLI from @airframeui/build.
npm install -D @airframeui/build
npx af theme exportBrowser playground: Theme Studio. Product page: Airframe → Figma. Working repo: examples/theme.
How it works
Section titled “How it works”- Brand the product in CSS (
:rootand[data-brand]). - Point
theme.filesat those stylesheets inairframe.config.js. npx af theme exportwrites DTCG JSON intotheme.outputDir.
Export layers, in order:
- Catalog defaults from
@airframeui/tokens - Breakpoints from
airframe.config.js(if you set them) - Each path in
theme.files, in array order
Later files win when the same token is set twice. Earlier values stay if a later file does not repeat them. Brands are discovered from [data-brand]. Do not list brand ids in config. Colours and fonts stay in CSS.
Config
Section titled “Config”Create airframe.config.js in the project root. npx af init writes a starter. af theme loads this file from cwd. --config picks another path.
/** @type {import('@airframeui/build').AirframeBuildOptions} */
export default {
theme: {
files: ['./src/tokens.css', './src/brands/*.css'],
outputDir: '.airframeui',
},
};| Key | What it does |
|---|---|
theme.files | CSS/SCSS with --af-* overrides. Globs are allowed. Split colour across files is expected. A comma-separated [data-brand] list applies to every brand in the list. |
theme.outputDir | Folder tokens/ is written into. Default .airframeui if you omit it. CLI -o / --out overrides. |
That is not top-level outputDir in the same file. That key is optional generated CSS for PostCSS / af build. See Build Tool.
Add .airframeui/ to .gitignore. Do not commit the export.
--css src/extra.css adds stylesheets for one export without editing config.
Commands
Section titled “Commands”| Command | Direction | Writes |
|---|---|---|
af theme export | CSS → JSON | tokens/<palette>/{light,dark,hc-*}.tokens.json |
af theme generate --from … | JSON/CSS → CSS | --af-* stylesheet (best-effort inbound) |
af theme lint | check CSS | diagnostics only |
af theme validate | check a file | the same report, no CSS written |
npx af theme export
npx af theme export -o ./figma-tokens
npx af theme export --css src/extra.css
npx af theme generate --from ./tokens.json -o theme.css
npx af theme lint theme.css
npx af theme validate ./tokens.json --format autoFormats for generate / validate: auto, dtcg, tokens-studio, css, figma-variables, style-dictionary, airframe-spec.
--from accepts a local file or an HTTPS URL to JSON/CSS (not an HTML page). --strict fails on warnings.
What export writes
Section titled “What export writes”Each af theme export replaces tokens/ so a brand you deleted in CSS does not linger. Other files in the output directory are left alone.
.airframeui/
tokens/
default/ ← :root palette
light.tokens.json
dark.tokens.json
hc-light.tokens.json
hc-dark.tokens.json
delta/ ← [data-brand='delta']
light.tokens.json
dark.tokens.json
hc-light.tokens.json
hc-dark.tokens.json
airframe.resolver.jsonSame four filenames in every folder so modes line up. default is :root. Every other folder is a [data-brand] id. Do not name a brand base. That collides with --af-base-*.
This is why most teams export. Designers drop the four files in tokens/default onto one collection. Each file is a mode. Same names as the app.
A second brand is a second collection with the same four filenames, so light / dark / high contrast still line up.
Figma does not read airframe.resolver.json.
Theme Studio downloads the same pack in the browser: four JSON files, four modes, one collection. Product page: Airframe → Figma.
Do not import a Figma or Tokens Studio dump back into Airframe and expect a complete theme. Names rarely match. Override CSS yourself, then export.
Generate and lint
Section titled “Generate and lint”Inbound is best-effort. The mapper is a small alias table (primary → --af-base-primary, plus --af-* names). Proprietary paths (color.blue.500, brand/500) land in the unmapped report, not in CSS. Dark and high-contrast companions are often missing.
Keep generate for CSS that already uses --af-*, for a round-trip of our own DTCG, or when you have renamed tokens to match the catalog. Then lint.
Import the generated theme.css after @airframeui/core.
This package
Section titled “This package”@airframeui/theme is the library behind the CLI. Dev dependency. Same version as core. It does not run in the browser. The app still needs @airframeui/core for runtime CSS.
npm install -D @airframeui/themeUse the library when you are writing your own script. Most apps stop at af theme export.
import { emitDtcgExport, resolveTheme } from '@airframeui/theme';
const spec = resolveTheme({ config, css });
const { palettes } = emitDtcgExport({ spec });
// palettes.default.light … palettes.delta.darkRelated
Section titled “Related”- Airframe → Figma — theming, Theme Studio, and this package
- Theme Studio — pick colours, copy CSS, download a Figma pack
- Theming — brand the app with CSS
- Build Tool —
af themeCLI - Token source of truth
- Example:
examples/theme