Theming & config
dssoca is configured along two orthogonal axes (see Introduction). The palette itself — why it is built this way — is explained in Color theory. This page covers
how to set them — statically and at runtime — and the dssoca.config.ts manifest that defines them.
The color axis — data-theme
data-theme selects the color palette: dark (default) or light. Set it on any ancestor; the
nearest one wins, so you can theme a subtree differently from the page.
<html data-theme="light"> … </html> The size axis — data-size-variant
data-size-variant scales the chrome: sm (compact) · md (default) · lg (oversized). Every
size-sensitive value is a token, so one flip rescales spacing, control padding, font sizes, and the
app-shell dimensions together.
Sizing resolves in three layers, highest priority first:
- a component’s
sizeprop — per instance componentsSize[Name]— a per-component defaultdata-size-varianton an ancestor — the global default (mdout of the box)
<script>
import { Button } from 'dssoca';
</script>
<!-- inherits the ambient size -->
<Button>default</Button>
<!-- opts this one instance out -->
<Button size="lg">larger</Button> The manifest — dssoca.config.ts
The axes, their allowed values, and the defaults are declared once in dssoca.config.ts, the
config source of truth. Everything else (types, runtime defaults) is derived from it.
import { dssocaConfig } from 'dssoca';
dssocaConfig.theme.values; // ['dark', 'light']
dssocaConfig.theme.default; // 'dark'
dssocaConfig.size.values; // ['sm', 'md', 'lg']
dssocaConfig.size.default; // 'md' Runtime helpers
When you need to flip an axis from code (a theme toggle, a density switch), use the helpers — they
read and write the same data-* attributes.
applyDesignConfig(partial, target?) — merge a partial config over the current one and write it to
an element (defaults to <html>). Flip one axis at a time:
import { applyDesignConfig } from 'dssoca';
applyDesignConfig({ theme: 'light' });
applyDesignConfig({ sizeVariant: 'sm' }); designAttributes(config?) — build the data-* attribute map for SSR/markup, so the right theme +
size paint on the first frame with no flash:
<html {...designAttributes({ sizeVariant: 'sm' })}> … </html> getDesignConfig() returns the current resolved config; resolveComponentSize(name, size?) is the
helper components use internally to apply the three-layer resolution above.
The theme and size buttons in this site’s top bar call
applyDesignConfigdirectly — the docs drive the system the same way your app would.
Per-component defaults
To bias specific components without changing the global size, pass componentsSize:
import { applyDesignConfig } from 'dssoca';
applyDesignConfig({
sizeVariant: 'md',
componentsSize: { Badge: 'sm', LogStream: 'sm' },
}); Components not listed inherit the global sizeVariant.
Custom palettes
The color axis is backed by 19 root palette slots per theme (bg, fg, accent + the 16
terminal slots); every semantic token derives from them, so replacing the slots recolors the
whole system. Pass a Palette to applyDesignConfig({ palette }) to apply one at runtime, or
emit a zero-JS CSS override block with paletteToCss(palette) (load it after dssoca/theme.css):
import { applyDesignConfig, paletteToCss, type Palette } from 'dssoca';
applyDesignConfig({ palette }); // runtime — tracks later theme flips
const css = paletteToCss(palette); // static — ship as a stylesheet Don’t hand-write the 38 hex values — the Theme Builder builds a palette interactively: pick an accent, live-preview real components, fix any WCAG failures with one click, and export exactly these two snippets.
Preset themes
Any terminal theme can be a website theme — and six well-known ones ship ready-made as PRESET_THEMES: Dracula (light = the official Alucard), Tokyo Night (Night + Day), Gruvbox, Nord (dark only), Solarized, and Coffee (light only). Resolve one with presetPalette() and feed it to either palette path:
import { applyDesignConfig, paletteToCss, presetPalette } from 'dssoca';
applyDesignConfig({ palette: presetPalette('dracula') }); // runtime
const css = paletteToCss(presetPalette('gruvbox')); // static CSS A preset only carries the modes its upstream defines; presetPalette() mirrors a single-mode
theme (Nord, Coffee) into both, so the theme toggle keeps the same colors. The palettes stay
faithful to the upstream hues, but slots that fail dssoca’s WCAG 2.2 AA contrast targets are
nudged along OKLCH lightness (hue untouched) — every nudge is commented in the source with the
upstream value. The Theme Builder offers each preset as an example button, so
you can load one, hand-tune any slot, and re-export it.