zudo-doc
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

Design Token Panel

作成 2026年4月22日更新 2026年10月10日Takeshi Takatsudo

スペーシング、フォント、サイズ、カラーの各デザイントークンをタブ分けしたパネルでライブ編集し、JSONでエクスポート・AIを介して読み込めるワークフローを提供します。

Design Token Panelは、テーマが提供するすべてのデザイントークンをページ上で編集できるインタラクティブなエディタです。以前のColor Tweak Panel(カラー専用)を置き換え、Palette・Color・Font・Spacing・Sizeの各トークン種別をタブ構成でカバーします。さらに統一されたJSONエクスポート/インポート機能を備えており、デザインをまとめてAIアシスタントに渡し、返ってきた結果を読み込むラウンドトリップ運用が可能です。

パネルを有効にする

zfb.config.ts で designTokenPanel を true に設定します:

zfb.config.ts
export default defineConfig(
  zudoDoc({
    designTokenPanel: true,
    // ...
  }),
);

有効になると、ヘッダーに(検索アイコンの左側に)パレットアイコンが表示されます。クリックするとパネルが開閉し、Escape を押せばページのどこからでも閉じられます。

Note

設定フィールドは designTokenPanel です。true に設定するとパネルが有効になります。ホスト側の設定ファイルは不要です — designTokenPanelConfigModule で独自のビルダーを指定しない限り、パネルはパッケージのデフォルトビルダー(@takazudo/zudo-doc/design-token-panel-config)を使用します(詳しくは下記のパネルのカスタマイズを参照)。

パネルのカスタマイズ

デフォルトでは designTokenPanel: true にホスト側の設定ファイルは不要です — 注入されるパネルはパッケージのデフォルトビルダー(@takazudo/zudo-doc/design-token-panel-config)を使用し、バンドルされたカラースキームから Palette/Color タブを、同梱のトークンマニフェストから Font/Spacing/Size タブを導出します。

完全にカスタムなパネル(独自のトークンマニフェスト、独自のカラースキーム)を用意するには、buildDesignTokenPanelConfig(mode: "light" | "dark") という名前付きビルダーをエクスポートするモジュールを作成し、designTokenPanelConfigModule にそのパスを指定します — プロジェクトルートからの相対パスで、chromeBindingsModule の契約をそのまま踏襲します:

zfb.config.ts
export default defineConfig(
  zudoDoc({
    designTokenPanel: true,
    designTokenPanelConfigModule: "./src/config/design-token-panel-config.ts",
  }),
);

このショーケースは、パッケージ所有のブートストラップとパッケージのデフォルトビルダーを使用します。自動注入されるブートストラップに独自のモードスコープなビルダーを読み込ませたい場合にのみ、designTokenPanelConfigModule を設定してください。

この設定が適用されるのは、パッケージ注入ルートでレンダリングされるページだけである点に注意してください: 設定が存在する間、自己完結型のホスト pages/ スタブでレンダリングされるドキュメントページは、パネルアイランド(およびヘッダーのパネルボタン)を一切マウントしません。これにより、スタブページがパッケージデフォルトのビルダーでセッション単位のパネル設定を横取りすることがなくなります。スタブでレンダリングされるページにもパネルを出したい場合は、クライアントのブートストラップを固定ターゲットのサーバー境界で包み、chromeBindings.DesignTokenPanelBootstrap に渡してください — この境界はどこでも優先されます(ホストクロームバインディングを参照)。

タブ構成

zudo-doc がパネル設定で渡しているトークンタブは、Palette・Color・Font・Spacing・Size の5つです。これに @takazudo/zdtp 自身が Inspect タブを先頭に追加します。Inspect はzdtpが合成するタブで、ホストの設定には現れず、設定側から取り除くこともできません。つまり実際のタブ列は常に設定した数より1つ多く、パネルは Palette を選択した状態で開きます。

設定している5つのIDはいずれもzdtp側の予約IDなので、汎用のティアレンダラーではなく、それぞれ専用のエディタが割り当てられます。各タブには担当するトークン以外は表示されないため、色の下までスクロールしてスペーシングにたどり着く必要はありません。

Inspect

ホスト側の設定に関わらず、zdtpが常に用意するタブです。パネルヘッダーから(または I キーで)有効にしてページ上の要素をクリックすると、その要素の計算値と、それが解決されるトークン(継承されたものを含む)が並べて表示されます。zfb.config.ts 側に設定項目はありません — このタブはパネルの機能であり、このプロジェクトのトークンマニフェストの一部ではありません。

Palette

Paletteタブは、すべてのカラースキームの土台となる、共有される3つのOKLCHランプを公開します(Color を参照):

  • Base — 5 ストップ(--palette-base-0 … --palette-base-4)、インデックス 0 が最も明るい

  • Accent — 3 ストップ(--palette-accent-0 … --palette-accent-2)

  • State — 4 つの名前付きロール: danger・success・warning・info(--palette-state-{role})

タブ上部の Edit / Check トグルで、同じランプに対する2つのビューを切り替えます。

  • Edit では、各ストップがzdtpネイティブのOKLCH明度/彩度/色相カーブエディタ上のスウォッチとして並びます。ストップをドラッグすると、そこから構築されたすべてのセマンティックロールがライブで更新されます — 別途の "Scheme…" プリセットドロップダウンはありません。ランプそのものが編集可能なソースオブトゥルースです。

  • Check は同じランプをコントラスト確認ビューに切り替えます。背景となるストップを選ぶと、前景側の候補それぞれのコントラストが一覧されるため、カーブを編集した結果をパネル内で確かめられます。

ウォークスルーはカラースキームプレビューを参照してください。

Color

Colorタブはセマンティック→ランプのエディタです。行は3つのグループに分かれ、4 つの base ロール(bg・fg・selection-bg・selection-fg)、--zd-* セマンティックロール、シンタックスハイライト用のロール(syntaxComment・syntaxKeyword・syntaxString など)が並びます。各行は Palette タブのランプ上のストップ、あるいは一部のロールではリテラルの OKLCH オーバーライドに紐付けられています。このタブ自体はランプを持たず、Palette タブの Base / Accent / State の各階層を参照するため、そこでランプストップを編集すると、それを指すすべての行の色が変わります。

Ref 行 — グループ化されたランプのドロップダウン

ほとんどの行は、Base / Accent / State の <optgroup> を持つ <select> としてレンダリングされ、Palette タブのランプのストップごとに 1 つのオプションが並びます。各オプションにはストップのCSS変数名と解決後の色が表示され、行そのものにも解決結果を示すカラーチップが付くため、ドロップダウンを開かなくても参照先が現在どの色になっているか分かります。

オプションを選ぶと、その行の --zd-* カスタムプロパティが var(--palette-{tier}-{n}) に紐付きます — 解決済みの色ではなく、ライブな CSS 変数参照です — そのため、Palette タブで参照先ストップの L/C/H カーブをドラッグするとページが即座に更新され、Colorタブで何かを選び直す必要はありません。

各 ref 行のドロップダウンの末尾には 「Literal…」 エントリもあり、行をランプから切り離して一度きりの色を固定できます。

Literal 行 — モードごとに AA 調整したオーバーライド

一部のロールは、両モードで共有ランプストップだけでは満たせず(モードごとのリテラルオーバーライドを参照)、デフォルトでリテラル行としてレンダリングされます:Literal… が選択された <select> と、編集可能な OKLCH スウォッチです。どのロールがリテラルで始まるかはスキームによって定義されます。同梱スキームでは、AA 調整されたステートカラー(danger は両モード、accentHover・success・warning・info は Default Light)、2 つのマッチキーワード用トークン、2 つの差分シンタックストークン、そしてリテラルなセマンティックロールを継承しているシンタックスロールがこれにあたります。

リテラル行のスウォッチには Per-mode チェックボックスがあります。オンにすると、1 つではなく 2 つの独立した OKLCH フィールド(Light / Dark)が現れます。適用される値は light-dark(<light-value>, <dark-value>) になり、パネルは適用先のルートに color-scheme: light dark を設定するため、ブラウザはアクティブなモードに対応する側を解決します。

マッチキーワード用トークン

検索結果でマッチしたキーワードのハイライト方法を制御する2つのセマンティックカラートークンがあります。これらはリテラル行としてレンダリングされ(ライトとダークで共有 — モードごとのリテラルオーバーライドを参照)、検索ウィジェット(pages/lib/_search-widget.tsx)が検索UIのヒット箇所のスタイリングで参照します。

  • matchedKeywordBg — マッチしたキーワードの背景に塗られる色。

  • matchedKeywordFg — その背景の上に重なる、マッチしたキーワードの文字色。

モードスコープの編集モデル

Colorタブは常に、現在アクティブなモード(ライトまたはダーク)の紐付けを編集し、パッケージの @takazudo/zudo-doc/color-schemes-defaults(または設定済みなら自作の colorSchemes 上書き — Color を参照)のそのモードの ColorScheme.map からシードされます。

  • 実効ライト/ダーク表示が変わると、タブの ref/literal のデフォルトが再シードされます — 新しいモードの紐付けに切り替わります(例:bg が base-0 ↔ base-4 と入れ替わる)。System 選択中の OS 設定変更も含まれます。この背後にある destroy+reconfigure の仕組みは実装を参照してください。

  • Palette・Spacing・Font・Size の編集は、外観変更をまたいでそのまま引き継がれます。 これらのタブはモードに依存しないため、ランプカーブの編集やスペーシングの変更は、これまでと同様にライト↔ダークをまたいで保持されます。

  • 保存された Color タブのオーバーライドは、スキームおよびモードスコープです。 パッケージのデフォルトビルダーはpanelSettings.colorModeでDefault LightとDefault Darkを対応付けるため、保存された Color オーバーライドはアクティブなスキーム識別子に対してのみ復元されます。一方のモードで行ったオーバーライドがもう一方を再配色することはありません。Palette・Spacing・Font・Size タブは外観変更をまたいで共有されます。

既知の制限

zudo-doc のビルダーはモードごとのリテラルデフォルトを宣言していません。 TierItem.default は単一の文字列なので、(danger のような)AA 調整されたモードごとのリテラルは、事前に {light, dark} のペアとして宣言するのではなく、再構成時にアクティブなモードからシードされます。ただし zdtp 側の制約ではありません: 0.4.5 以降、Color タブの colorExtras.semanticDefaults マップが行ごとに { literal: { light, dark } } を受け取れるようになっており、これがそうしたデフォルトを設定する正規の手段です。パッケージのデフォルトビルダーがまだこのマップを埋めていないだけです。実行時のモードごとの編集(上記の Per-mode チェックボックス)は影響を受けません — これは設定が開始時のデフォルトとして宣言する内容を制限するだけです。

Font

タブに表示される順に、5 つのティアがあります。

  • Scale — 生の --text-scale-* ステップ(2xs → 2xl)。CSS値のサニタイズ付きの数値入力で編集します。

  • Font size — セマンティックロール(text-micro … text-display)。これは参照ティアで、各行は生の値ではなく Scale のステップを選びます。そのためステップを編集すると、それを指すすべてのロールに波及します — Colorタブのセマンティック行がランプストップを指すのと同じ構造です。

  • Line height・Font weight・Font family — 残りのタイポグラフィトークン。フォントファミリーは、複数スタックのフォールバックを含む任意の有効な font-family 値を受け付けます。無効な値(引用符の不一致、生のJavaScriptなど)は入力確定時に拒否されるため、貼り付けたスニペットによってページが壊れることはありません。

各ティアには、書体サンプル・行送り・ウェイト・ファミリーのライブプレビューが付きます。さらに、サイトの実際のフォントで組んだ読み取り専用のスペシメンをホストページ側に表示させることもできます(表示中はパネルが一時的に右ドックに固定されます)。

Spacing

ティアは 4 つ: Horizontal spacing(hsp-*)・Vertical spacing(vsp-*)・Icons(icon-xs → icon-lg)・Layout。編集可能なステップには数値コントロールと、値に応じて伸縮するプレビューバーが付きます。数値の一括操作(乗算・加算・ステップ単位の丸め・一括設定)を使えば、選択した範囲の行をまとめて変更できます。

Layout のうち 3 つは読み取り専用として表示されます: spacing-0(ユーティリティが前提にしている構造的なゼロ)・spacing-px(1px のヘアライン)・sidebar-w(単一のコントロールでは表現できないレスポンシブな clamp() 式)。存在を把握してもらうために見せているだけで、動かすためのものではありません。

Size

ティアは 2 つです。名前から想像しがちなアイコンサイズはここにはなく、Spacing タブにあります。

  • Radius — --radius-DEFAULT・--radius-lg・--radius-full。最後のひとつにはピルトグルがあり、9999px のセンチネル値と編集可能な値を切り替えられます。

  • Transition — デフォルトのトランジション時間。

パネルのシェル

タブ以外にも、パネルのシェル自体が備えている機能がいくつかあります。探す前に把握しておくとよいものを挙げます。

  • ドックモード。 フロート・右ドック・下ドック・折りたたみのミニピルの4つがあり、Alt+1 … Alt+4 で切り替えます。2 つのドックはホストドキュメント側の領域を確保し、パネルを閉じると解放するため、ページはパネルの裏に隠れるのではなく脇に回り込みます。選んだモードはページをまたいで保持されます。

  • アイドル時のゴースト表示。 操作していない間はパネルを薄く表示するモードです。色の変更をページ全体で確かめたいときに使えます。

  • ヒストリーレールと A/B スナップショット。 編集の取り消し/やり直しに加えて、トークンの状態をまるごと保存して切り替えられるスロットが 2 つあります。

  • トークン検索とコマンドパレット。 全タブ横断のあいまい検索(タブごとのヒット数付き)と、目的のトークンへ直接飛べる Cmd/Ctrl+K のコマンドパレットです。

  • 変更トークンの可視化。 編集した行にはマークが付き、タブにはバッジが表示され、フッターに合計("N tokens changed across M tabs")が出ます。Changed only で変更行だけに絞り込み、Copy diff で差分をクリップボードにコピーし、Revert all ですべて元に戻せます。Font・Spacing・Size の各タブには、そのタブだけを戻す Reset も用意されています。

  • チェーンポップオーバー。 トークンごとの解決チェーン — 何を参照しているか、何から参照されているか、現在のページで実際にいくつの要素が使っているか — を表示します。

キーボードアクセシビリティ

タブの切り替えは標準的なWAI-ARIA Tabsパターンを実装しており、シェル側にもパネル全体のショートカットがあります:

キー動作
← / →前/次のタブにフォーカスを移動
Home最初のタブにフォーカス
End最後のタブにフォーカス
Enter / Spaceフォーカス中のタブをアクティブ化
Escapeパネルを閉じる
Alt+1 … Alt+4フロート/右ドック/下ドック/ミニピルに切り替え
Cmd/Ctrl+Kコマンドパレットを開く
I要素インスペクトを有効化(そのあと要素をクリック)

タブは自動アクティブ化方式で、矢印キーでフォーカスを移動するとパネルの表示も切り替わります。各タブ内のコントロールはすべて Tab で辿れ、いずれにも可視のフォーカスリングが用意されています。

Apply がこのショーケースで無効な理由

パネルには、現在の差分をHTTPエンドポイント経由でソースファイルへ書き戻す Apply ボタンがあります。ただしこのショーケースでは意図的に機能しません。zdtpはApplyの有効化条件として applyEndpoint と空でない applyRouting マップの両方を要求しますが、zudo-doc のパッケージデフォルトビルダーはそのどちらも設定していないためです。ボタンは無効のままで、"Apply unavailable: configure an apply endpoint and a non-empty routing map." というツールチップが表示されます。ここでサポートされるラウンドトリップ手段は、以下のJSONエクスポート/インポートです。

JSONエクスポート — 既定では差分のみ

パネルヘッダーの Export をクリックすると、エクスポートモーダルが開きます。モーダルには、各タブの現在の状態を表す単一のJSONドキュメントが表示され、タブ ID をキーとする tabs オブジェクトでラップされています。

既定のエクスポートはデフォルトとの差分です — 実際に変更したトークンだけが含まれます。まったく触っていないタブは丸ごと省略され、変更があったタブのなかでも編集したトークンだけが残ります。差分は小さく、diffしやすく、コミットに貼り付けても安定した出力になります。

{
  "$schema": "zudo-design-tokens/v3",
  "exportedAt": "2026-07-05T12:00:00.000Z",
  "tabs": {
    "palette": {
      "raw": {
        "--palette-accent-1": "oklch(0.700 0.158 62)"
      }
    },
    "color": {
      "semantic": {
        "--zd-bg": { "ref": { "tab": "palette", "tier": "base", "item": "base-3" } },
        "--zd-danger": {
          "literal": { "light": "oklch(.505 .170 25)", "dark": "oklch(.655 .170 25)" }
        }
      }
    },
    "spacing": {
      "raw": { "--spacing-hsp-md": "1.25rem" }
    }
  }
}

$schema は、変更されたすべての値がプレーンな文字列またはパレットインデックスの数値である間は zudo-design-tokens/v2 ですが、いずれかの Color タブの行が {ref} または {literal} オブジェクトを持った瞬間に自動的に /v3 へアップグレードします — モードスコープのモデルでは、これは実際の zudo-doc のエクスポートでは通常のことです。ref は Palette タブのランプストップ({tab, tier, item})を指し、literal は単一の OKLCH 文字列か、Per-mode 行の場合は {light, dark} のペアのいずれかです。Load で再インポートすると、どちらの形状もきれいにラウンドトリップします。

Load from JSON… で Color タブの literal に単一の light-dark(...) 文字列を読み込むと、スウォッチを開いたときに式についての説明が表示され、HEX 入力と色のスライダーは無効になります。Edit as literal を選ぶと操作できるようになり、色を編集すると式がリテラルの色に置き換わります。この単一文字列の読み込みは、上で説明した Per-mode の {light, dark} ペアとは異なります。

モーダルヘッダーの Show defaults too トグルを有効にすると、完全なトークンツリー(すべてのタブ、すべてのトークン、未変更のデフォルトを含む)を出力できます。テーマの全容を知らないデザイナーやAIに渡すスナップショットが必要な場合は、この形式を使ってください。

JSONから読み込み

Load ボタンを押すとインポートモーダルが開きます。以前のエクスポートやAIが生成したJSONドキュメントを貼り付けると、パネルは次の処理を行います:

  1. 形状を検証(バージョン・既知のキー・値の妥当性)。

  2. 不明なキーや不正な値を致命的でない警告として報告。

  3. ドキュメントを現在のデフォルトにマージ。未指定のトークンはデフォルトのまま、明示されたトークンだけが上書きされます。

  4. 結果を localStorage に永続化し、すべてのCSSカスタムプロパティを即時に再適用。

不正なJSONは具体的なエラーメッセージとともに拒否されます。spacing.hsp.md だけを変更するような部分的なインポートも、正規のユースケースとしてサポートされます。

AIワークフロー

差分のみのエクスポートとJSONロードを組み合わせると、チャット型AIとの単純なラウンドトリップが実現できます:

  1. 渡したいトークンを編集(触らなくてもOK)。

  2. 差分をエクスポートしてJSONをコピー。

  3. AIチャットに貼り付け、自然言語でリクエストを添える。例:

    これは現在のデザイントークンの差分です。カラーパレットはそのままに、より温かみがあり、コントラストの強いタイポグラフィスケールに書き換え、JSONだけを返してください。

  4. AIが返したJSONを Load に貼り付け。

  5. パネルが検証・マージ・反映を即座に行います。結果が気に入らなければ、変更トークンのツールバーにある Revert all ですべて巻き戻せます。

既定のエクスポートが差分になっているため、AIは気にしているトークンだけを読むことになり、未変更のデフォルトを推理する必要がありません。AIに全体像が必要な場合(例: ゼロから新しいテーマを作らせるとき)にだけ Show defaults too をオンにしてください。

永続化

パネルが記憶する内容はすべて、パッケージのデフォルトビルダーが固定しているストレージプレフィックス zudo-doc-tweak の配下に置かれます。トークンの状態そのものは単一のバージョン付きエンベロープに入り、残りはパネルのシェルや機能ごとの状態です。

キー内容
zudo-doc-tweak-state-v4統合トークンエンベロープ。各タブの状態を横並びに保持します。カラー状態はアクティブなスキーム識別子ごとにキー付けされるため、ライトとダークの編集を独立して復元できます。旧形式の -state-v3・-state-v2・-state も読み込まれ、前方に移行されます。
zudo-doc-tweak-openパネルを開いたままにしていたか
zudo-doc-tweak-position・-sizeフロート時の位置とサイズ
zudo-doc-tweak-dock・-dock-sizeドックモード(float / right / bottom / mini)とドックの寸法
zudo-doc-tweak-spawn-ordinalパネルのカスケード表示位置。body の入れ替えをまたいで保持されます
zudo-doc-tweak-densityタブグリッドの密度設定
zudo-doc-tweak-ghostアイドル時のゴースト表示設定
zudo-doc-tweak-specimen・-on-page-specimenフォントスペシメンのツールバー設定と、スペシメンをホストページ上に表示するかどうか
zudo-doc-tweak-snapshot-a・-snapshot-bA/B スナップショット
zudo-doc-tweak-last-appliedApply の比較基準(Apply が無効なこのサイトでは未使用)
zudo-doc-tweak:visible・zudo-doc-tweak:autoload遅延読み込みの表示意図フラグと、オーナーモードの自動読み込みフラグ
zudo-doc-tweak-elpath-enabled・-domtweaker-enabledエレメントパスピッカー/DOM Tweaker の有効フラグ
zudo-doc-tweak-highlight-slots・-highlight-outline-widthトークンハイライトのスロット色とアウトライン幅
zudo-doc-tweak-highlight-activeアクティブなハイライトのマップ。ここだけは localStorage ではなく sessionStorage に保存されます

このキー一覧は @takazudo/zdtp が所有しており、将来のリリースで増える可能性があります。zudo-doc が保証するのはプレフィックスであって、個々のキーではありません。

Revert all は全タブの変更トークンをまとめて元に戻し、Font・Spacing・Size タブの Reset はそのタブだけを戻します。いずれも設定済みのデフォルトに復帰させる操作です。ストレージ形式とライフサイクルはインストール済みの @takazudo/zdtp パッケージが所有し、zudo-doc 自身は永続化エンベロープを解析・変換しません。

実効ライト/ダーク表示が変わっても保存済みの編集が消えることはなく、開いているパネルは表示変更をまたいで開いたままになります。外観メニューは実効表示が変わった場合だけ color-scheme-changed イベントをディスパッチし、ホストはパネルをその場でパッチするのではなく、新しいモード用に destroy して再構成します(実装を参照)。そのため、Color タブの ref/literal のデフォルトは新しくアクティブになったモードに追従し、保存済みの Color オーバーライドもそのモードのスキーム識別子に対して復元されます。デバイス設定と現在の表示が一致しているときに System を選んだ場合は、保存される設定だけが変わり、パネルは再構築されません。Palette・Spacing・Font・Size の編集はそのまま引き継がれます。モードスコープの編集モデルを参照してください。

ストレージプレフィックスの継続性保証

ストレージプレフィックス zudo-doc-tweak は、パッケージのデフォルトビルダー(@takazudo/zudo-doc/design-token-panel-config、このショーケースもそのまま利用しています)に固定されており、変わりません。そのため、以前のリリースで保存した編集内容もそのまま引き継がれます。それ以外の永続化の詳細は @takazudo/zdtp が所有し、リポジトリ内の zudo-doc 互換レイヤーには属しません。

ランタイム依存とCSS

インストールされた公開@takazudo/zdtp 0.8.6は、preact: ^10.29.1を自身の依存として含みます(0.8.5まではプロジェクト側でインストールが必要なpeerでした)。パネルを有効にする場合やカスタムマウント用にバンドルする場合も、zdtpをインストールするだけで済みます。zudo-doc自体のコンポーネントはzudo-reactを使い、Preactノードを必要としません。パネルは独立したPreactサブツリーとTailwind browser engineを所有し、サイトのユーティリティを登録しません。

pnpm add @takazudo/zdtp@0.8.6
@import "@takazudo/zdtp/styles.css";

./styles.cssと./stylesは同じ配布CSSの公開エクスポートです。他の先頭インポートと一緒に置き、物理的なdist/パスを参照しないでください。スキャフォールドが追加するのはパネル機能を選択した場合だけです。

実装

パネルUIは @takazudo/zdtp(zdtp)npmパッケージが提供します。パッケージ所有の DesignTokenPanelBootstrap アイランドと、configurePanel の呼び出し、zfb のナビゲーションライフサイクルへのフック、および後述のモードスコープな destroy+reconfigure の仕組みは @takazudo/zudo-doc/design-token-panel-bootstrap にあります。固定ターゲットのサーバー境界がクライアントbootstrapをマウントし、scope.onActivate内でrunDesignTokenPanelBootstrapOnce(buildDesignTokenPanelConfig, "default", scope.abortSignal)を呼び出します。buildDesignTokenPanelConfig は (mode) => PanelConfig のビルダーであり、これが Color タブをライト/ダークに追従させる仕組みです。アイランドがハイドレートすると、パネルはその副作用として自己マウントされます。

遅延読み込み

@takazudo/zdtp は初期ページバンドルには含まれません。bootstrapDesignTokenPanel はマウント時に小さな暫定クリックリスナーを登録するだけで、実際の zdtp の動的インポート(とそれに続く configurePanel の呼び出し)は、ヘッダーのトリガーが最初に toggle-design-token-panel をディスパッチしたときに実行されます。インポートが解決する前に届いたクリックはキューにためられ、configure完了後に正味1回分の表示/非表示にまとめられるため、すばやい連続クリックが二重に発火することはありません。

ブートストラップは、パッケージ所有のサブパス @takazudo/zudo-doc/zdtp-loader を経由してのみ zdtp を読み込みます。プリセットは、zdtp がバンドルされていない場合 — bundleZdtp ?? designTokenPanel として解決されます — にこの指定子だけをスタブモジュールに差し替えます。そのため bundleZdtp を一度も設定しないプロジェクトは、これまでどおりの挙動のままです: パネルがオフなら zdtp のチャンクは一切出力されません。bundleZdtp: true を設定すれば、パネルがオフのままでも本物のローダーを維持できます — その理由は自前のパネルをマウントするを参照してください。ホスト側で独自に書いた import "@takazudo/zdtp" には、どちらの場合も影響しません。

保存済みの状態を持つ再訪ユーザーは、そのクリックを待つ必要がありません。マウント時にブートストラップは、アクティブな(パックスコープの)ストレージプレフィックス配下の localStorage を確認し、以下のいずれかが真であれば、操作前に即座に zdtp を読み込みます:

  • パネルが開いたままだった(${prefix}-open が "1")

  • トークンオーバーライドが保存されていた(${prefix}-state* というキーが存在する)

  • オーナーモードのフラグが設定されている(${prefix}:autoload・${prefix}-elpath-enabled・${prefix}-domtweaker-enabled のいずれか)

${prefix}-open とオーナーモードのチェックはキーを直接指定した参照ですが、${prefix}-state* のチェックだけは、その時点で localStorage に存在するすべてのキーを走査します(プレフィックスで問い合わせるネイティブAPIは存在しないため)。ただし、アクティブなプレフィックスの厳密な語幹で始まるキーだけをヒットとして扱うため、すべてのキー名には目を通しつつも、無関係な別アプリ自身の *-state キーに誤反応することはありません。保存済み状態を持つテーマパックへの切り替えも、同様の即時読み込みを引き起こします。

いずれの経路でも zdtp が読み込まれるまでは、window.zdtp(zdtp が構成完了時にインストールするコンソールAPI)は存在しません。一度読み込まれると、そのページが存続する間はその読み込まれた状態を保ち続けます — トグルイベントは zdtp 自身のリスナーが直接引き継ぎます。この遅延状態に戻るのは、ページを丸ごと再読み込みしたときだけです。

実効表示が変わったときにディスパッチされる color-scheme-changed イベント(System 選択中の OS 変更を含む)のたびに、ブートストラップは新しいモードを読み取り、素早い連続変更を 1 つのマクロタスクにまとめてから、handle.destroy() に続けて configurePanel(buildDesignTokenPanelConfig(mode)) を呼び出します — zdtp の configurePanel は、構造的に異なる設定でその場で再実行すると例外を投げるため、destroy してから再構成することが、Color タブのモードスコープなデフォルトを差し替える唯一のサポートされた方法です。保存設定が変わっても実効表示が同じ場合は theme-preference-changed イベントで通知し、パネルは再構築しません。パネルが開いていた場合は、開いた状態で再マウントされます。

ヘッダーのトリガーボタンは window に toggle-design-token-panel カスタムイベントをディスパッチします。zdtpはこのイベントをネイティブに受け取るため、headerRightItems フィールドでトリガーをカスタマイズしても追加の配線は必要ありません。

自前のパネルをマウントする

designTokenPanel と bundleZdtp はまったく別のことを制御しており、これを混同したことが zudo-doc#4261 の原因そのものでした。designTokenPanel が制御するのはマウント(パッケージ所有の DesignTokenPanelBootstrap アイランドを描画するかどうか)で、bundleZdtp が制御するのはバンドル(@takazudo/zdtp をビルドに含めるかどうか)です。両者はデフォルトで互いに連動します(遅延読み込みを参照)が、パッケージのパネルではなく自前のパネルアイランドをマウントしたいホストは、この2つを独立に設定する必要があります。

パッケージのアイランドが呼んでいるのと同じブートストラップを、自前の "use client" アイランドから呼び出します。その際、bootstrapDesignTokenPanel を直接呼ぶのではなく runDesignTokenPanelBootstrapOnce を経由してください。再レンダリングやソフトナビゲーションで2回目のブートストラップが走るのを防ぐのが、この once ラッチの役割です。2回ブートストラップされると toggle-design-token-panel のリスナーが二重に登録され、トリガーを1回クリックしただけでトグル意図が2回分としてカウントされ、パネルが開かなくなります。

"use client";

import { getScope } from "@takazudo/zfb/zudo-react";
import { runDesignTokenPanelBootstrapOnce } from "@takazudo/zudo-doc/design-token-panel-bootstrap";
import { buildDesignTokenPanelConfig } from "@/config/design-token-panel-config";

export function HostPanelBootstrap() {
  const scope = getScope();
  scope.onActivate(() => {
    runDesignTokenPanelBootstrapOnce(buildDesignTokenPanelConfig, "configured", scope.abortSignal);
  });
  return null;
}

HostPanelBootstrap を静的にインポートし、Island({ when: "load", children: <HostPanelBootstrap /> }) を Fragment で包んで返すサーバーコンポーネントを BodyEndIslands に渡します。クライアントのブートストラップはハイドレーション後に起動し、SSR 中にはパネルを設定しません。バインディングオブジェクト経由で渡す場合も Fragment を維持してください。

これを機能させるには、2つの設定を連動させて変更します:

  • designTokenPanel: false — パッケージ側は何もマウントしません。パネルを描画するのは自前のアイランドだけになります。

  • bundleZdtp: true — ローダーを本物のまま維持します。パネルをオフにしたままこれを未設定にすると、@takazudo/zudo-doc/zdtp-loader は例外を投げるスタブに差し替わり、ビルド自体は正常に成功したように見えても、パネルを開いた瞬間に自前のブートストラップの動的インポートが失敗します。

トリガーもホスト側の担当です。designTokenPanel: false にすると、settings.headerRightItems の組み込み design-token-panel トリガーは除外されます(パッケージ側のパネルアイランドが無い状態でイベントだけをディスパッチする「死んだボタン」を描画しないため)。そのため自前のパネルには自前のボタンが必要です — headerRightComponents 経由で解決される headerRightItems エントリでも、任意の要素でもかまいませんが、window に toggle-design-token-panel をディスパッチしてください。

@takazudo/zdtp(@takazudo/zudo-doc のオプショナルなピア依存)自体のインストールと、そのスタイルシートのインポート — 自前の global.css に @import "@takazudo/zdtp/styles.css" を書くこと — もホスト側の作業です。この行を代わりに書いてくれるものはここにはありません: create-zudo-doc がこの行を書き込むのは、designTokenPanel をオンにしてスキャフォールドしたときだけです。

bundleZdtp: true のまま @takazudo/zdtp がインストールされていない場合、@takazudo/zudo-doc/zdtp-loader の静的再エクスポートの解決に失敗し、ビルドが失敗します。これは意図的な、サイレントなランタイム障害よりも望ましい失敗のさせ方です。

無効な組み合わせ

designTokenPanel: true と bundleZdtp: false の組み合わせは、設定解決の時点で拒否されます。パッケージのパネルがマウントされているのにローダーがスタブ化されていると、開いた瞬間に確実に例外が発生するため、zudo-doc はそれをビルドしてしまう代わりにビルドを失敗させます。

設定リファレンス

設定型説明
designTokenPanelbooleanパッケージ自身のパネルアイランドをマウントします。デフォルトは false。
bundleZdtpboolean@takazudo/zdtp をビルドにバンドルします。デフォルトは undefined(designTokenPanel に追従: bundleZdtp ?? designTokenPanel)。designTokenPanel: false のまま true にすると、パッケージのパネルはマウントせずに zdtp だけをバンドルします — 自前のパネルをマウントするための組み合わせです(自前のパネルをマウントするを参照)。designTokenPanel: true のまま false にすると設定解決の時点で拒否されます。
designTokenPanelConfigModulestring完全にカスタムなパネル用に buildDesignTokenPanelConfig(mode) をエクスポートするモジュールへの、プロジェクトルート相対パス。デフォルトは undefined(パッケージのデフォルトビルダーを使用)。

デフォルトのトークンそのもの(スペーシングスケール・フォントスケール・アイコンサイズ・パレットのエイリアス)は@takazudo/zudo-doc/theme.cssから提供されます。スキャフォールドの後続のsrc/styles/global.cssにある:rootブロックはオーバーライドポイントです。カラーランプとマッピングには、パッケージの@takazudo/zudo-doc/color-schemes-defaultsまたは自作のcolorSchemes上書き(Colorを参照)を使います。パネルはブラウザ内のコピーを編集するだけで、ソースファイルに書き戻すことはありません。

Tip

気に入った組み合わせが見つかったら、差分をエクスポートしてコミットメッセージやデザインドキュメントに貼り付けてみてください — いま行った変更を再現するもっとも小さな説明になります。

Revision History

Takeshi Takatsudo作成: 2026-04-23T02:37:52+09:00更新: 2026-10-10T19:10:25+09:00

AI Assistant

Ask a question about the documentation.

Preview theme

Loading theme previews…