Define the theme

Point theme tokens at the palette, keep light-dark() to colors, and avoid Core internals.

Map the palette to tokens

A theme token is a named slot that Astryx components read for a value — --color-accent for the accent color, and so on. Components never read your palette directly; they read tokens. Defining a theme means pointing each token at a palette shade, so the components wear your colors.

Import the palette in oceanTheme.ts and point your tokens at its stops. Each token takes a [light, dark] pair — the shade to use in light mode and the one in dark mode.

ts
// themes/ocean/oceanTheme.ts
import {defineTheme} from '@astryxdesign/core/theme';
import {palette} from './tokens/ocean.palette';
​
const {light, dark} = palette.ocean;
​
export const oceanTheme = defineTheme({
name: 'ocean',
tokens: {
'--color-accent': [light['45'], dark['70']],
},
});

Local imports must stay inside the theme folder. One that leaves it, such as ../../shared/colors, fails with invalid_theme, and the theme disappears from theme list. npx astryx theme template writes a file that explains every defineTheme field. For the full token set, scope selectors, and component theming, read astryx docs theme.

Build on another theme

To base a theme on an existing one, extends it: import the base theme and override only the tokens you change. The derived theme keeps a live link to the base and inherits its later changes — unlike --from, which forks a copy (astryx docs cli/integrations/building-blocks/themes/add-a-theme).

ts
import {defineTheme} from '@astryxdesign/core/theme';
import {oceanTheme} from './oceanTheme';
​
export const oceanContrastTheme = defineTheme({
name: 'ocean-contrast',
extends: oceanTheme,
tokens: {
'--color-accent': ['#0051a3', '#4aa3ff'],
},
});

Keep light-dark() to colors

Each [light, dark] pair compiles to a light-dark() value, which switches only colors. Give it colors. For a value that is not a plain color — a gradient — put light-dark() on each color stop, not around the whole value: a browser without light-dark() drops the declaration, and the stop form is the one that degrades safely.

Do not set Core private variables

Core private variables start with --_, such as --_field-radius. They are internals and can change in any Core release, so theme build reports each one it finds as an [error]. Set the standard CSS property instead — borderRadius, padding — and let the build emit the internal variable where Core needs it.

Declare the peer dependencies

The theme imports @astryxdesign/core/theme, so declare Core as a peer dependency, with the range of Core versions you test the theme against — a range, not an exact version, so a Core patch release does not force a republish. integration add theme already declared the optional @astryxdesign/cli peer that reads themes:

json
"peerDependencies": {
"@astryxdesign/core": "^0.7.0",
"@astryxdesign/cli": ">=0.7.0"
},
"peerDependenciesMeta": {
"@astryxdesign/cli": {"optional": true}
}