Zudo Token Panel
GitHub repository

Type to search...

to open search from anywhere

Panel CSS tokens

--tokentweak-* private variables, the self-contained dark palette baked into panel-tokens.css, the modal data-attribute selector, and the host-adapter import obligation.

The panel ships its own bundled CSS — no Tailwind dependency in the consumer, and no reads against the host's --color-* theme. This page pins the panel-private --tokentweak-* namespace, the self-contained dark palette the panel paints with, the bundled stylesheet's modal-selector contract, the host-layout dock variables, and the panel-private override surface for hosts that want a different chrome theme.

Panel-private namespace

The bundled stylesheets declare every panel-chrome variable under a panel-private namespace, scoped to the panel shell, modal data attribute, and body-level feature surfaces:

:where(
  .tokenpanel-shell,
  .tokenpanel-mini-pill,
  [data-design-token-panel-modal],
  .tokenpanel-highlight-settings-popover,
  .tokenpanel-chain-popover,
  .tokenpanel-color-picker,
  .tokenpanel-tooltip,
  .tokenpanel-elpath-label,
  .tokenpanel-elpath-toast,
  .tokenpanel-element-inspect-box,
  .tokenpanel-element-inspect-label,
  .tokenpanel-element-inspect-view
) {
  --tokentweak-pad-md: 12px;
  --tokentweak-gap-sm: 20px;
  --tokentweak-text-body: 19px;
  --radius-tokentweak:;
  /* …every panel-chrome value lives here */
}

Naming rules

  • Panel-private color, font, spacing, typography, and z-index vars use the --tokentweak-* prefix. The shared radius token is the existing --radius-tokentweak name; no consumer-namespaced identifiers may appear in the panel chrome.

  • The chrome stylesheet (panel.css) MUST read only package-owned tokens (--tokentweak-*, --radius-tokentweak, and component-local layout hints such as --tokenpanel-grid-min) — it MUST NOT read host vars like --color-* or --font-mono directly.

  • The token sheet (panel-tokens.css) declares the --tokentweak-* values and --radius-tokentweak as concrete values (no var(--color-*) reads) so host theme changes cannot bleed into the panel chrome. See the self-contained palette below.

  • The host-layout coordination variables use a separate --zdtp-dock-inset-* namespace. They are written on the document root only while a dock claim is active and are not panel-chrome retheme hooks.

Files

  • panel.css — chrome layout / typography / controls.

  • panel-tokens.css — the --tokentweak-* declarations.

Both ship from the package, combined into a single dist/zdtp.css by the Vite library build. The CSS is also embedded as a string in dist/index.js via a ?inline import and is automatically injected as a <style> element when the panel first mounts — consumers do not need to import the stylesheet manually.

The ./styles sub-export (alias ./styles.css) resolves to dist/zdtp.css and remains available as an optional explicit import for consumers who want the CSS in their own pipeline (SSR hydration, PostCSS, bundler deduplication):

// Optional — only needed to pull CSS into your own pipeline
import '@takazudo/zdtp/styles';

No Tailwind dependency

The package MUST build and run without Tailwind in the consumer. The panel JSX uses hand-authored CSS classes backed by --tokentweak-* vars exclusively.

PanelConfig.modalClassPrefix controls the BEM root for every modal the panel owns (export, import, apply). The host picks any string and the panel emits classes like ${modalClassPrefix}__overlay, ${modalClassPrefix}__panel, ${modalClassPrefix}__header, etc.

The bundled CSS keys on the data attribute, NOT on the class prefix. Every modal <dialog> element emits data-design-token-panel-modal="" (with data-design-token-panel-modal-variant set to "apply" / "export" / "import"). panel.css anchors all modal chrome rules on [data-design-token-panel-modal] and matches sub-elements via [class*='__title']-style attribute selectors.

This means a host that customises modalClassPrefix still inherits the bundled chrome — selecting on the literal class prefix would leave any non-default host with unstyled modals.

The class prefix remains useful as a higher-specificity hook for hosts that want to layer custom rules on top of the bundled chrome.

Self-contained panel chrome palette

The panel-chrome color tokens are declared in panel-tokens.css as semantic aliases onto a private OKLCH ramp. The panel reads NOTHING from the host's --color-* / --font-mono theme — host theme changes (including theme tweaks driven through this very panel in a demo) cannot bleed into the panel chrome:

:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
  /* base-0 is the darkest ground; stops ascend toward the foreground. */
  --tokentweak-palette-base-0: oklch(0.18 0 0);
  --tokentweak-palette-base-1: oklch(0.25 0 0);
  --tokentweak-palette-base-2: oklch(0.34 0 0);
  --tokentweak-palette-base-3: oklch(0.536 0 0);
  --tokentweak-palette-base-4: oklch(0.66 0 0);
  --tokentweak-palette-base-5: oklch(0.8 0 0);
  --tokentweak-palette-base-6: oklch(0.91 0 0);
  --tokentweak-color-fg: var(--tokentweak-palette-base-5);
  --tokentweak-color-bg: var(--tokentweak-palette-base-0);
  --tokentweak-color-muted: var(--tokentweak-palette-base-4);
  --tokentweak-color-border: var(--tokentweak-palette-base-3);
  --tokentweak-color-surface: var(--tokentweak-palette-base-1);
  --tokentweak-color-accent: #d69a66;
  --tokentweak-color-accent-bar: #efb477;
  --tokentweak-color-accent-hover: #a7c0e3;
  --tokentweak-color-code-bg: var(--tokentweak-palette-base-2);
  --tokentweak-color-code-fg: var(--tokentweak-palette-base-6);
  --tokentweak-color-success: #93bb77;
  --tokentweak-color-danger: #da6871;
  --tokentweak-color-warning: #dfbb77;
  --tokentweak-font-mono: Menlo, Monaco, Consolas, 'Liberation Mono',
    'Courier New', monospace;
}

The palette mirrors a terminal-style "Default Dark" scheme — achromatic neutrals with a warm accent and a cool accent-hover — so the panel reads as a separate dark surface on top of any host backdrop. The private --tokentweak-palette-base-0 through --tokentweak-palette-base-6 ramp is numbered from the darkest ground upward; the semantic color roles below alias those stops.

Public surface

These are the panel-private variables a host MAY override on the same scope to retheme the panel chrome:

VariableDefaultRole
--tokentweak-color-fgoklch(0.8 0 0)Foreground text.
--tokentweak-color-bgoklch(0.18 0 0)Recessed wells and inverse ink on accent fills.
--tokentweak-color-mutedoklch(0.66 0 0)Muted and secondary text.
--tokentweak-color-borderoklch(0.536 0 0)Borders and dividers.
--tokentweak-color-surfaceoklch(0.25 0 0)Panel shell and raised surfaces (cards, modals).
--tokentweak-color-accent#d69a66Primary actions and highlights.
--tokentweak-color-accent-bar#efb477Changed-state rails and compact markers.
--tokentweak-color-accent-hover#a7c0e3Hover state for accent surfaces.
--tokentweak-color-code-bgoklch(0.34 0 0)Inline / block code background.
--tokentweak-color-code-fgoklch(0.91 0 0)Inline / block code foreground.
--tokentweak-color-success#93bb77Success state colour.
--tokentweak-color-danger#da6871Danger / error state colour.
--tokentweak-color-warning#dfbb77Warning state colour.
--tokentweak-font-monosystem monospace stackMonospace font for code / values.

Override surface for hosts

A host that wants a different chrome theme assigns directly to the --tokentweak-* names on .tokenpanel-shell, [data-design-token-panel-modal], or any ancestor (the panel scope uses :where() so specificity is 0):

:root {
  --tokentweak-color-bg: #102030;
  --tokentweak-color-fg: #eef;
  --tokentweak-color-accent: #ffb74d;
}

This is the entire host-override contract for panel chrome. --color-* and --font-mono are NOT part of the override surface — assigning to them on the host page has no effect on the panel.

A host may also override one --tokentweak-palette-base-* stop to move every semantic role that aliases it. Direct --tokentweak-color-* assignments still win because the panel's defaults use zero-specificity :where(). --tokentweak-color-muted now affects secondary text only; hosts that previously used it to recolor both text and 1px dividers must also assign --tokentweak-color-border.

The non-color token scales are concrete pixel values: --tokentweak-pad-* is 2/6/8/12/16/24/32px for 2xs/xs/sm/md/lg/xl/2xl, --tokentweak-gap-* is 7/14/20/24/28/40/56px for the same steps, and --tokentweak-text-* is 12/14/16/19/22/48/60px for micro/caption/small/body/subheading/heading/display. The shared radius is --radius-tokentweak: 4px. The semantic z-index values are exposed as --tokentweak-z-overlay, shell, settings-popover, color-picker, tooltip, command-palette, inspector-box, and toast in the high integer band used by the runtime.

Z tokenValue
--tokentweak-z-overlay2147482990
--tokentweak-z-shell2147482991
--tokentweak-z-settings-popover2147482992
--tokentweak-z-color-picker2147482993
--tokentweak-z-tooltip2147482994
--tokentweak-z-command-palette2147482995
--tokentweak-z-inspector-box2147483000
--tokentweak-z-toast2147483001

Dock and page-specimen variables

Docked modes publish one host-layout variable on document.documentElement:

VariableWritten whileMeaning
--zdtp-dock-inset-rightdockMode: 'right'Current right dock width in pixels.
--zdtp-dock-inset-bottomdockMode: 'bottom'Current bottom dock height in pixels.

The variables are restored to their exact prior inline declarations when the claim is released. With dock.reflow: 'body-margin' the matching body margin is also set; with 'none' the body margin is restored while the root variable remains available to host layout CSS during the claim.

The on-page specimen uses host-facing classes rather than the panel shell: .tokenpanel-on-page-specimen, .tokenpanel-on-page-specimen-heading, .tokenpanel-on-page-specimen-section, and .tokenpanel-on-page-specimen-row. It inherits the host font and foreground color, uses Canvas as its background, and marks each line-height sample with the inline --tokenpanel-specimen-line guide variable. The specimen node is data-zdtp-specimen and is excluded from panel-owned scans. The current implementation does not emit a .zdtp-specimen class; use the class and data attribute above as the stable selector.

Invariant — the panel package MUST NOT read host theme vars

Neither panel.css nor panel-tokens.css may reference --color-* or --font-mono. The package's CI pins this with grep checks:

grep -n 'var(--color-' src/styles/panel.css        # → 0
grep -n 'var(--font-mono' src/styles/panel.css     # → 0
grep -n 'var(--color-' src/styles/panel-tokens.css # → 0
grep -n 'var(--font-mono' src/styles/panel-tokens.css # → 0

Why no host theme reads?

The panel is a developer tool that ships inside a host page. If the panel inherited the host's --color-* tokens, any host theme change — including theme tweaks driven by the panel itself in a demo — would recolor the panel chrome along with the host. The dev tool would visually merge with the surface it is debugging, which is the opposite of what a dev tool should do. Keeping the palette self-contained makes the panel a stable visual anchor regardless of host theme state.

Host-adapter side-effect import (paired-unit obligation)

The consumer MUST own a side-effect import for the host-adapter, paired with <DesignTokenPanelHost>. The ./styles import is optional because the panel entry self-injects its stylesheet; use it only when the host wants a static CSS pipeline. The component AND a sibling <script> block loading @takazudo/zdtp/astro/host-adapter are a single unit — both lines are required, always together.

Required wiring shape:

<DesignTokenPanelHost config={myPanelConfig} />

<script>
  void import('@takazudo/zdtp/astro/host-adapter');
</script>

Why a dynamic void import('...')?

Both forms work — the package's package.json lists dist/astro/host-adapter.js in sideEffects so Rollup preserves consumer-side imports of the host-adapter regardless of whether the result is used. The dynamic form is the recommended canonical wiring because it loads the host-adapter chunk off the critical page-load path (mirrors the existing color-presets lazy-loader pattern) and is robust to future packaging changes that could miss-configure sideEffects.

Why not a single page-level static import?

Browser caching makes the duplicated import() cheap (one network fetch per session), and the wrapper component is the single authoritative mount point so duplicating the import there is a non-issue.

What happens if you skip it?

Skipping this import leaves the JSON config payload from <DesignTokenPanelHost> on the page with no JS to read it, so calling window.<consoleNamespace>.showDesignPanel() throws ReferenceError. Symptom in deployed builds: silent failure, no panel chrome ever paints.

The ./astro/host-adapter sub-export points at the built dist/astro/host-adapter.js file plus its .d.ts types.

Consumer-controlled tokens

The tokens the panel writes to (the cssVar field on each TierItem, plus color-tab base-role and semantic names) are entirely consumer-controlled. Hosts pick names like --myapp-spacing-hgap-md, --myapp-p0, and --myapp-semantic-bg themselves; the panel writes them through the default :root sink or the configured applySink.

The package contract is therefore:

  • Read: the panel never reads consumer CSS variables for its own chrome (it carries defaults via TierItem.default).

  • Write: the panel only writes consumer-supplied cssVar strings, plus color-tab palette/base/semantic vars, through the active sink.

Cross-references

  • PanelConfig.modalClassPrefix — BEM root for modal classes (the data attribute is what the bundled CSS keys on).

  • Token manifest — declares the cssVar names the panel writes to the default root or configured applySink.

  • Color cluster — declares the palette / base-role / semantic CSS-var names the panel writes on apply.

Revision History

CreatedUpdated