Use a theme

Apply a theme to your app: wrap in a provider, pick a theme, switch dark mode, nest themes, and choose runtime or built for production.

Wrap your app in a theme

Install a theme package
bash
npm install @astryxdesign/theme-neutral
Basic theme setup (runtime injection)
tsx
import {Theme} from '@astryxdesign/core';
import {neutralTheme} from '@astryxdesign/theme-neutral';
​
function App() {
return (
<Theme theme={neutralTheme}>
<YourApp />
</Theme>
);
}
Optimized setup (pre-built CSS)
tsx
import {Theme} from '@astryxdesign/core';
import {neutralTheme} from '@astryxdesign/theme-neutral/built';
import '@astryxdesign/theme-neutral/theme.css';
​
function App() {
return (
<Theme theme={neutralTheme}>
<YourApp />
</Theme>
);
}

Each theme ships as its own npm package. Install the one you want, then wrap your app in <Theme>. The same pattern works for every theme; just swap the package and import name.

The default import uses runtime style injection, which works everywhere with no build step. The /built import skips injection and relies on the pre-compiled CSS file for better performance and SSR support.

Available Themes

Install the theme package you want with npm install @astryxdesign/theme-{name}, then import its theme object as shown below.

ThemeImportDescription
Neutralimport {neutralTheme} from '@astryxdesign/theme-neutral'Muted, minimal aesthetic with Figtree typography. A good starting point.
Butterimport {butterTheme} from '@astryxdesign/theme-butter'Golden, buttery surfaces with blue accents; Sarina + Outfit type.
Chocolateimport {chocolateTheme} from '@astryxdesign/theme-chocolate'Warm brown tones and cozy beige; Fraunces + Albert Sans type.
Gothicimport {gothicTheme} from '@astryxdesign/theme-gothic'Dark-only atmospheric theme; deep blue-gray surfaces, distressed display type.
Matchaimport {matchaTheme} from '@astryxdesign/theme-matcha'Earthy greens; DM Sans + Playwrite US Trad type.
Stoneimport {stoneTheme} from '@astryxdesign/theme-stone'Warm stone and slate tones; Montserrat + Figtree type.
Y2Kimport {y2kTheme} from '@astryxdesign/theme-y2k'Playful Y2K pop; periwinkle body, holographic accents, Poppins + Crimson Text.

All theme packages export from two subpaths: - @astryxdesign/theme-{name}: source theme (runtime injection) - @astryxdesign/theme-{name}/built: pre-built theme (pair with theme.css)

Theme Props

<Theme> takes theme (required), mode ('system' by default, or 'light'/'dark'), and children. For every prop, run astryx component Theme.

Using a Theme from an Integration

Install the integration as a direct dependency and Astryx discovers its source themes and guide topics without an astryx.config file. Install Core too because the copied source imports defineTheme from @astryxdesign/core/theme.

Install, inspect, copy, and build
bash
npm install @astryxdesign/core @acme/brand-integration
astryx theme list --package @acme/brand-integration
astryx docs brand-theme
astryx theme add ocean --package @acme/brand-integration
astryx theme build src/themes/ocean/oceanTheme.ts

The copy is editable project source, not a reference back into node_modules. The complete theme directory comes with it, including its typed .doc.mjs, nested token and palette modules, and receipts. A second add refuses to overwrite those files unless you pass --overwrite.

Dark mode

Use [light, dark] tuples in token values for automatic mode switching. Use mode='system' (default) on Theme to follow OS preference.

Light/dark tuple
tsx
'--color-accent': ['#0064E0', '#2694FE'],
// ^light ^dark
Toggle with a button
tsx
const [mode, setMode] = useState<'light' | 'dark'>('light');
​
<Theme theme={myTheme} mode={mode}>
<Button
label={mode === 'light' ? 'Switch to Dark' : 'Switch to Light'}
onClick={() => setMode(m => (m === 'light' ? 'dark' : 'light'))}
/>
</Theme>;

To create a theme with custom dark mode colors, see astryx docs author-a-theme.

Nested themes

Wrap different sections in separate <Theme> providers.

Dark sidebar with light content
tsx
<Theme theme={lightTheme} mode="light">
<Layout
header={<LayoutHeader>...</LayoutHeader>}
start={
<Theme theme={darkTheme} mode="dark">
<LayoutPanel>{/* Dark sidebar */}</LayoutPanel>
</Theme>
}
content={<LayoutContent>{/* Light content */}</LayoutContent>}
/>
</Theme>

Runtime vs Built Themes

Themes work in two modes:

Runtime (source)Built
Import (published theme)@astryxdesign/theme-{name}@astryxdesign/theme-{name}/built + theme.css
Import (custom theme)defineTheme() directlyBuilt .js + .css from astryx theme build
How it worksuseInsertionEffect injects <style> at hydrationPre-compiled .css file loaded with the page
Component overridesInjected client-onlyIn static CSS: present during SSR
SSR safeTokens yes, component overrides flash on hydrationFully SSR safe: no flash
Best forDev, prototyping, client-only SPAsProduction, SSR apps (Next.js, Remix)
GuidancePractices
Do

Use the /built subpath + theme.css for production SSR apps.

Do

Use runtime themes during development for fast iteration.

Do

Run astryx theme build for custom themes to get the built artifacts.

Don't

Use runtime themes in production SSR apps; component overrides will flash on hydration.

Don't

Import /built without the CSS file; component overrides won't apply.

To build a custom theme for production, see the Build section of astryx docs author-a-theme.