CSS-in-JS
@unpunnyfuns/swatchbook-integrations/css-in-js exposes a typed JS accessor whose leaves are var(--<cssVarPrefix>-*) string references. It drops into any ThemeProvider that passes its theme through as-is: emotion, styled-components, or a hand-rolled provider. The toolbar switches every value at once through the CSS cascade.
Install
Section titled “Install”npm install -D @unpunnyfuns/swatchbook-integrationsNo additional Vite plugins needed; the virtual module is plain JavaScript.
Configure
Section titled “Configure”import { defineMain } from '@storybook/react-vite/node';import cssInJsIntegration from '@unpunnyfuns/swatchbook-integrations/css-in-js';
export default defineMain({ addons: [ { name: '@unpunnyfuns/swatchbook-addon', options: { configPath: '../swatchbook.config.ts', integrations: [cssInJsIntegration()], }, }, ],});Import in any story or component:
import { theme, color, space, radius, shadow } from 'virtual:swatchbook/theme';What gets generated
Section titled “What gets generated”Per-group exports plus an aggregate theme constant, one leaf per DTCG path.
The example below assumes cssVarPrefix: 'sb' in your config; the default is swatch, so variables and attributes use --swatch-* / data-swatch-* instead.
export const color = { "accent": { "bg": "var(--sb-color-accent-bg)", "bgHover": "var(--sb-color-accent-bg-hover)", "fg": "var(--sb-color-accent-fg)" }, "surface": { "default": "var(--sb-color-surface-default)", },};export const space = { "md": "var(--sb-space-md)",};
export const theme = { color, space, radius, shadow, typography };Values are stable across tuples: flipping the toolbar changes nothing in this module, it changes what the --sb-* variables resolve to. See Consuming the active theme for the cascade mechanism.
With a provider (emotion / styled-components):
import { ThemeProvider } from '@emotion/react';import { theme } from 'virtual:swatchbook/theme';
export default { decorators: [ (Story) => <ThemeProvider theme={theme}><Story /></ThemeProvider>, ],};const Button = styled.button` background: ${(props) => props.theme.color.accent.bg}; padding: ${(props) => props.theme.space.md};`;Or direct references, no provider:
import { color, space } from 'virtual:swatchbook/theme';
<div style={{ background: color.surface.raised, padding: space.lg }} />Naming
Section titled “Naming”- Dashed DTCG segments (
color.accent.bg-hover) render ascolor.accent.bgHover. CamelCased for valid JS identifiers without bracket notation. - Numeric segments render bare (
color.palette.neutral.500→color.palette.neutral[500]). Leading-zero numerics (size.050) stay quoted because bare050is an octal under strict mode.
What this doesn’t do
Section titled “What this doesn’t do”- Doesn’t produce a resolved-value theme. Leaves are
var()references, not literal colours. For libraries that derive dependent slots at factory time (MUI’screateThemecomputingpalette.primary.light/contrastText), you need literal values: run Terrazzo’s CLI with@terrazzo/plugin-js. - Doesn’t handle composite tokens structurally. A DTCG
typographycomposite lives as a singlevar()reference, not as{ fontFamily, fontSize, … }. If your library needs the sub-fields, same caveat. - Doesn’t auto-inject a
ThemeProvider. You wire it yourself.