Zudo Token Panel
GitHub repository

Type to search...

to open search from anywhere

Static token dashboard

Render a plain token reference page from shared tabs with the Preact TokenDashboard component.

Render a token inventory inside your documentation page with the named TokenDashboard Preact component. The same tabs data can drive your panel and this read-only page. A static host can render it during the build and ship HTML plus CSS with no dashboard hydration.

Availability

The dashboard is available from npm v0.6.1 and in theworkspace demo. This documentation site's panel still uses its separate pinned npm dependency. The optional imperative client API isunreleased and is not in this site's pinned 0.8.6 package; see thedashboard reference.

Keep token definitions build-safe

Put your tab definitions in a data module with type-only imports. The dashboard page should import that module directly. Keep configurePanel(), browser globals, storage access, and host-adapter imports in your panel's browser entry.

// token-tabs.ts — data only; safe to import during a site build.
import type { TabConfig } from '@takazudo/zdtp/dashboard';

export const tokenTabs: readonly TabConfig[] = [{
  id: 'space',
  label: 'Spacing',
  tiers: [{
    id: 'scale',
    label: 'Scale',
    preview: 'bar',
    items: [{
      id: 'space-md',
      cssVar: '--site-space-md',
      label: 'Medium',
      default: '1rem',
      type: { kind: 'length', step: 0.25, unit: 'rem' },
    }],
  }],
}];

Pass tokenTabs as tabs in your existing PanelConfig too. This shares the source definitions; it does not connect the dashboard to the panel's live state.

Render a Preact page

Use a host that renders Preact and configure TSX with jsxImportSource: "preact" when needed. ZDTP owns Preact as a regular dependency; the host should still declare Preact for its own JSX/SSR code. The dashboard import does not initialize the panel or require the panel stylesheet.

// TokenPage.tsx — ordinary Preact TSX, rendered by your static host.
import { TokenDashboard } from '@takazudo/zdtp/dashboard';
import { tokenTabs } from './token-tabs';

export default function TokenPage() {
  return <TokenDashboard tabs={tokenTabs} mode="light" title="Site tokens" />;
}

No client island is needed for a static page. If your host uses Preact's server renderer directly, render this component with preact-render-to-string as part of the host's normal build. The package supplies a component, not an HTML-export API or CLI. A React adapter is outside this checkpoint.

Include the separate stylesheet

The component's JavaScript does not import CSS. Include @takazudo/zdtp/dashboard/styles.css once through your host's CSS pipeline. A portable static-host approach is to copy the public package export into its public assets directory at build time, then link it from the page head:

// scripts/copy-dashboard-css.mjs — run before your site build.
import { copyFile, mkdir } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';

await mkdir('public/vendor', { recursive: true });
await copyFile(
  fileURLToPath(import.meta.resolve('@takazudo/zdtp/dashboard/styles.css')),
  'public/vendor/zdtp-dashboard.css',
);
<link rel="stylesheet" href="/vendor/zdtp-dashboard.css" />

Run the copy script from the host project root; adapt public/ and the URL for your framework and deployment base. The playground uses a build hook to perform this copy for both static builds and dev boot. Its page uses normal stylesheet links, so styling remains present with JavaScript disabled.

Bundlers that emit CSS from JavaScript imports can instead use this import in a layout or stylesheet entry:

import '@takazudo/zdtp/dashboard/styles.css';

Do not assume every static host handles that side-effect import. A host that only processes global CSS needs a resolvable CSS @import in that pipeline or the explicit asset copy and link above. Verify the emitted HTML and CSS.

Follow the host theme

Set color-scheme on a host ancestor to make the dashboard shell, backgrounds, and labels follow it. For example, let your application's theme switch update data-theme on html:

html { color-scheme: light; }
html[data-theme='dark'] { color-scheme: dark; }
<TokenDashboard tabs={tokenTabs} chrome="host" mode="light" title="Light inventory" />
<TokenDashboard tabs={tokenTabs} chrome="host" mode="dark" title="Dark inventory" />

The dashboard uses no media query, so an explicit application selection wins over the OS preference. Its chrome uses dedicated CSS custom properties and never reads inventory tokens. Omitting chrome keeps the default fixed light appearance; chrome="dark" fixes a dark appearance regardless of the host.

mode still selects declared per-mode defaults and the specimens' own color-scheme. Host and inventory modes are independent: host light × inventory light, host light × inventory dark, host dark × inventory light, and host dark × inventory dark all work. In the demo, switch “Dark host” to check all four combinations across the two inventories. That switch works entirely through CSS.

For one inventory that follows the page in both its chrome and its mode-aware rows, use host for both props:

<TokenDashboard
  tabs={tokenTabs}
  chrome="host"
  mode="host"
  title="Page-following inventory"
  id="page-following"
/>

The four public chrome inputs can be set on an ancestor, so one instance can carry a custom palette without changing its siblings:

<div style="--zdtp-dashboard-light-bg: #fff7ed; --zdtp-dashboard-light-fg: #7c2d12; --zdtp-dashboard-dark-bg: #1c1917; --zdtp-dashboard-dark-fg: #fed7aa">
  <TokenDashboard tabs={tokenTabs} chrome="host" mode="host" title="Warm dashboard chrome" />
</div>

Those inputs are --zdtp-dashboard-light-bg, --zdtp-dashboard-light-fg, --zdtp-dashboard-dark-bg, and --zdtp-dashboard-dark-fg. The dashboard keeps them inherited and derives its background, foreground, muted text, borders, cards, diagnostics, and sample surfaces with light-dark() and color-mix(). The root remains transparent, allowing the host page to own the surrounding surface.

Show both modes or embed a subset

Render two instances with mode="light" and mode="dark". Each preview scope sets its own color-scheme and local variable declarations; neither writes to :root. The default mode is light. Optional id values belong to the caller and must be unique when provided; no IDs are autogenerated.

For a compact reference, pass a subset of the tab data and constrain the host container's width. Include the tiers that referenced tokens depend on, or the reference will be shown with a diagnostic instead of a sample. The demo shows both complete modes and a narrow embedded spacing reference.

Compose three filtered instances

Mode dependence is computed per row, including rows that reference a mode-dependent row. A mixed tier therefore appears in both regions after partitioning. To publish one compact listing with two mode snapshots and one shared section, render each dependent row once for each mode and each independent row once overall:

<TokenDashboard
  tabs={tokenTabs}
  mode="light"
  include="mode-dependent"
  title="Light-dependent tokens"
  id="tokens-light"
/>
<TokenDashboard
  tabs={tokenTabs}
  mode="dark"
  include="mode-dependent"
  title="Dark-dependent tokens"
  id="tokens-dark"
/>
<TokenDashboard
  tabs={tokenTabs}
  chrome="host"
  include="mode-independent"
  title="Shared tokens"
  id="tokens-shared"
/>

The mode-dependent rows occur once in each of the first two instances, while the independent rows occur once in the third. Include referenced tiers in the same source data when building a subset; hidden declarations remain available to resolve the visible aliases.

Use TierConfig.preview for existing preview metadata. For text-editor colors or shadows, previewOverrides selects samples by CSS variable without creating a second manifest:

<TokenDashboard
  tabs={tokenTabs}
  previewOverrides={{
    // These keys must match variables in your tabs.
    '--site-accent': 'color',
    '--site-card-shadow': 'shadow',
  }}
/>

Supply your own reading passage

Spacing uses actual-size rulers and palette tiers use grouped discrete stops. Typography uses wide rows so line wrapping and line height can be compared. Supply a favorite passage at build time:

<TokenDashboard
  tabs={[...tokenTabs, {
    id: 'type', label: 'Typography', tiers: [{
      id: 'body-size', label: 'Body size', preview: 'size', items: [{
        id: 'body', label: 'Body', cssVar: '--site-body-size', default: '18px',
        type: { kind: 'length', step: 1, unit: 'px' },
      }],
    }],
  }]}
  previewText={'A quiet page gives each sentence room to breathe.\n\n好きな文章で、文字の大きさと行間を確かめましょう。'}
/>

This is a static prop, not an editable field. Omitting it uses longer English/Japanese prose; previewText="" keeps specimens empty. Fonts use local availability and CSS fallbacks. Rulers support nonnegative px/rem, zero, and resolved direct aliases; unsupported lengths remain readable without guessed geometry. Large rulers and palette strips scroll locally and accept keyboard focus. See the reference for grouping rules, specimen baselines, and preview limits.

What the page confirms

The inventory shows declared defaults: item defaults, per-mode colorExtras.semanticDefaults, and explicit baseDefaults. Reference rows show their declared source and corresponding CSS/reference text. Named color scheme presets, panel initialization, and saved edits are not applied, so the panel's initial or current values can differ. Pill rows retain item.default, including a sentinel such as auto, rather than substituting customDefault.

Expressions such as calc(), var(), and light-dark() remain expressions. Samples use the browser's actual CSS context; they are not a promise of computed pixel sizes, installed fonts, or resolved colors in every host. Missing external variables and other context-dependent values remain readable with diagnostics. Ambiguous, cyclic, missing, or unsafe declarations have no misleading sample. Arbitrary notes HTML and URL/mask assets are not rendered or loaded.

See the dashboard reference for the public props and preview behavior, and token manifest reference for the shared data types.

Revision History

CreatedUpdated