-
Notifications
You must be signed in to change notification settings - Fork 0
Theming
🔄 Auto-generated mirror. Canonical source:
docs/theming.md. Edit there — changes here are overwritten by CI.
Nav: Quick start · Writing cases · Hierarchy · Tweaks · Theming · Style engines · Documentation panel · Writing placard docs · Testing · CLI · AI agents · Configuration
Components render in an isolated document so what you see (and what the check runner screenshots) is exactly the component, with no showcase chrome leaking in. Theming is controlled in three places: global styles, an optional decorator, and per-render URL parameters. (For components styled by a runtime CSS-in-JS library like emotion/MUI, see Render-time styling below.)
List your CSS entrypoints in the config. Their contents are concatenated and injected into both the browse shell and the isolated render document, so components render with their real tokens and styles.
// display-case.config.ts
import { defineConfig } from '@awarebydefault/display-case'
export default defineConfig({
title: 'Display Case',
roots: ['src/components/**/*.case.tsx'],
globalStyles: ['./src/tokens.css', './src/components.css'],
})Paths are resolved relative to the package. A listed file that does not exist is silently skipped.
The isolated render reads a theme query parameter and sets it on the document root before rendering:
/render/tweak-control/variants?theme=light
/render/tweak-control/variants?theme=dark
It applies as <html data-theme="light"> (or "dark"). The render document also sets data-theme-pref to the same value, so an app ThemeProvider rendered via the decorator (e.g. behind a nav ThemeToggle) initializes to the harness theme instead of re-resolving from the OS and fighting the ?theme= selection. Any value other than dark is treated as light. Author your tokens against this attribute:
:root[data-theme='dark'] {
--bg: #111;
--fg: #eee;
}The check runner exercises both themes for every case, so a baseline is captured per theme. See Testing.
A decorator is a single React wrapper rendered around every case — the place for a theme provider, context, or a fixed frame.
// display-case.config.ts
import { defineConfig } from '@awarebydefault/display-case'
import { ThemeProvider } from './src/components/theme-provider'
export default defineConfig({
title: 'Display Case',
roots: ['src/components/**/*.case.tsx'],
decorator: ThemeProvider,
})The decorator accepts { children } plus the active case's level, sourcePath, and area — so beyond cross-cutting context it can wrap page/flow cases in app chrome (nav/header/footer). It wraps the rendered case (and the viewport-width wrapper, if any) inside React StrictMode. Use it for cross-cutting context that every component needs; prefer per-case composition for anything component-specific. See Configuration › decorator for the full signature and the per-area chrome pattern.
Global styles and the decorator cover static CSS and providers. But Material UI (and any emotion / styled-components library) emits its CSS while a component renders — so server rendering keeps the markup but loses the styling, giving an unstyled snapshot and a flash on first paint.
A style engine fixes that: it collects the render-time CSS during the server
render and delivers it before scripting. Configure it alongside the decorator —
the engine handles the server-side extraction, the decorator provides the
ThemeProvider your components need:
styleEngines: [emotionEngine],
decorator: ({ children }) => <ThemeProvider theme={theme}>{children}</ThemeProvider>,See Style engines for the full emotion/MUI recipe and the contract for other libraries.
In the browse chrome, the header carries a Chrome-DevTools-style device toolbar: a Responsive mode (full or a preset width — Desktop/Tablet/Mobile — with manual zoom) and fixed device sizes (1080p, 4K, laptop, iPad, iPhone, Pixel, Galaxy, or a custom W × H with a rotate button) that render the iframe at exact pixels and auto-scale to fit the panel. No URL parameter is involved — the toolbar sizes the iframe element directly.
For the standalone /render endpoint (snapshots, direct navigation), constrain the width with the width query parameter (in pixels) instead:
/render/page/dashboard?width=480
The case is wrapped in a centered container with max-width: <width>px. This is handy for previewing responsive behavior or capturing a narrow snapshot. Omit it for the default full-width render.
-
Configuration for the full
globalStyles/decoratorreference and defaults. -
AI agents for combining
theme,width, and tweak parameters into a single deterministic render URL.
Auto-generated mirror of the Display Case docs. Edit the repo, not the wiki.
Product documentation
- AI Agents
- CLI
- Configuration
- Documentation Panel
- Examples
- Hierarchy
- Quick Start
- Style Engines
- Testing
- Theming
- Tweaks
- Writing Cases
- Writing Placard Docs
Contributing (engineering)