HtmlPreview
ビューポート切り替えとソースコード表示を備えたインタラクティブなHTML/CSSプレビューコンポーネント。
<HtmlPreview> は、分離された iframe 内で HTML/CSS のライブデモを描画するコンポーネントです。ビューポートプリセット(Mobile / Tablet / Full)とシンタックスハイライト付きの折りたたみ可能なソースコードパネルを備えています。すべての MDX ファイルでインポートなしで使用できます。
基本的な使い方
<HtmlPreview
title="基本的なボックス"
html={`
<div class="box">Hello, world!</div>
`}
css={`
.box {
padding: 24px;
background: #3b82f6;
color: #fff;
border-radius: 8px;
font-family: system-ui, sans-serif;
text-align: center;
}
`}
/>レスポンシブレイアウト
ビューポートボタン(Mobile / Tablet / Full)を使って、異なる幅でコンテンツがどのように変化するかを確認できます。プレビュー領域の右下にあるドラッグハンドルでリサイズすることもできます。
HTML のみ
css プロップを指定しない場合は、HTML のソースのみが表示されます。
デフォルトでコードを表示
defaultOpen を指定すると、ソースコードが最初から展開された状態で表示されます。
<button class="btn">Click me</button>.btn {
padding: 10px 20px;
background: #8b5cf6;
color: #fff;
border: none;
border-radius: 6px;
font-size: 14px;
font-family: system-ui, sans-serif;
cursor: pointer;
}
.btn:hover {
background: #7c3aed;
}固定高さ
height プロップを使って、自動調整の代わりに iframe の高さを固定できます。
高さ100%
fullHeight プロップを使うと、プレビュードキュメントの html/body を iframe いっぱいに広げられます。height: 100% がビューポートまで届くレイアウト(利用可能なスペースを埋めるフレックスカラムなど)に便利です。
明示的な height と併用する
fullHeight は高さ自動調整の仕組みと干渉します — 高さ自動調整は iframe の body を計測して iframe の高さをそれに合わせますが、fullHeight は逆に body の高さを iframe 側から導出させます。両方を組み合わせると、安定した解決策のないフィードバックループが発生します。fullHeight を使うときは必ず明示的な height も指定してください。
外部リソース
CSS フレームワーク、Web フォント、スクリプトなどの外部リソースをプレビューに読み込めます。zfb.config.ts でグローバルに設定するか、コンポーネントのプロップで個別に指定します。
グローバル設定
zfb.config.ts で htmlPreview を設定すると、すべてのプレビューにリソースが適用されます:
export default defineConfig(
zudoDoc({
htmlPreview: {
head: `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP&display=swap">`,
css: `body { font-family: 'Noto Sans JP', sans-serif; }`,
js: `console.log('preview loaded');`,
},
}),
);コンポーネント単位のプロップ
head と js プロップを使って、個別のプレビューにリソースを追加できます。グローバル設定の後にマージされます。
<HtmlPreview
title="JS 付き"
html={`
<div id="output">待機中...</div>
`}
css={`
#output {
padding: 16px;
font-family: system-ui, sans-serif;
color: #334155;
}
`}
js={`
document.getElementById('output').textContent = 'JS から Hello!';
`}
/>外部スタイルシートとスクリプト
head と js は文字列ベースのプロップで、常に可視の「Head」/「JS」コードブロックとして表示され、プレビューには preflight リセット(すべてのプレビューに注入される Tailwind v4 の CSS リセット)が常に上乗せで適用され、独自リセットを持つフレームワークでもスキップする手段がありません。externalStyles・externalScripts・preflight・showResources は、CDN リソース(CSS フレームワーク、Web フォント、@tailwindcss/browser・Bootstrap・htmx のようなスクリプト)向けに、コードパネルを意識した構造化された代替手段を提供します。
externalStyles— スタイルシート URL の配列。<link rel="stylesheet" href="...">タグとして出力されます。author のcssより前に読み込まれるため、cssでフレームワークを上書きできます。externalScripts— スクリプト URL の配列。<script src="...">タグとして出力されます。インラインのjsプロップと同じサンドボックス/syncDelayの導出ロジックを通るため、プレビューは自動的にsandbox="allow-scripts allow-same-origin"と 300ms の高さ再同期ディレイを得ます。preflight—falseを指定すると、注入される preflight リセットを完全にスキップします。Tailwind のように独自のベーススタイルを持つフレームワーク向けです。showResources— 両方の配列は(head/jsと異なり)デフォルトでは可視のコードパネルから除外されます。読者に読み込まれているリソースを示したい場合はtrueを指定すると、「HTML」パネルの先頭に<link>/<script src>の生の行として表示されます。
これら4つのプロップはコンポーネント単位のみです — head/css/js と異なり、zfb.config.ts のグローバル htmlPreview 設定には含まれません。
外部リソースはクライアントサイドで読み込まれ、ビルド時には読み込まれない
externalStyles/externalScripts は、プレビューの iframe が描画されるときにブラウザが行うネットワークリクエストであり、ビルド時にバンドルされるアセットではありません。リソースの読み込み中はプレビューが一瞬スタイル未適用の状態で表示されることがあり、そのURLでリソースが利用可能であり続けることに依存します。
@tailwindcss/browser は独自のリセットを持つため preflight={false} を指定する、Tailwind CDN の1行デモ:
<HtmlPreview
title="Tailwind CDN"
externalScripts={["https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"]}
preflight={false}
html={`
<div class="flex gap-4 p-6 bg-slate-100">
<div class="px-4 py-2 bg-blue-500 text-white rounded-lg font-sans">Tailwind</div>
<div class="px-4 py-2 bg-emerald-500 text-white rounded-lg font-sans">via CDN</div>
</div>
`}
/>showResources を指定すると、CDN の URL が非表示ではなく「HTML」コードパネルの先頭に生の行として表示されます:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="px-4 py-2 bg-violet-500 text-white rounded-lg font-sans w-fit">コードを開くとCDNの行が見えます</div>セキュリティと sandbox プロップ
プレビューは分離された <iframe srcdoc> 内に描画されます。その sandbox 属性は、プレビューにスクリプトが含まれる場合(js プロップ、head 内の <script>、または空でない externalScripts)は allow-scripts allow-same-origin、含まれない場合は allow-same-origin をデフォルトとします。
信頼の前提
allow-scripts と allow-same-origin を組み合わせると、iframe のサンドボックスは実質的に無効化されます — プレビュー内のスクリプトが親ページのオリジンを共有し、親ドキュメントにアクセスできます。zudo-doc がこのデフォルトを採用しているのは、プレビューの内容が作成者が信頼できる MDX であるためで、また allow-same-origin が高さの自動計測を可能にしているためです。
半信頼またはユーザー投稿の HTML を描画するプロジェクトでは、sandbox プロップでより厳しい値に上書きしてください。
<!-- 最も厳格: スクリプト実行なし、オリジンは不透明 -->
<HtmlPreview html={untrusted} sandbox="" height={400} />
<!-- スクリプトは許可するがオリジンは不透明(親にアクセス不可) -->
<HtmlPreview html={untrusted} sandbox="allow-scripts" height={400} />allow-same-origin を外すと iframe のオリジンが不透明になり、親から iframe.contentDocument を読み取れなくなります — つまり高さの自動調整が無効になります。厳しい sandbox を指定するときは、必ず固定の height も併用してください。空文字列 "" はそのまま尊重され、プロップを省略したときだけ計算済みのデフォルトにフォールバックします。
Props
| プロップ | 型 | デフォルト | 説明 |
|---|---|---|---|
html | string | (必須) | プレビュー iframe 内に描画する HTML コンテンツ |
css | string | undefined | プレビュー iframe 内に適用する CSS スタイル |
head | string | undefined | <head> に挿入する生の HTML(リンク、メタ、フォント) |
js | string | undefined | プレビュー iframe 内で実行する JavaScript |
title | string | undefined | プレビューヘッダーバーに表示するタイトル |
height | number | auto | iframe の固定高さ(ピクセル)。省略時はコンテンツに合わせて自動調整 |
defaultOpen | boolean | false | ソースコードパネルをデフォルトで展開表示する |
fullHeight | boolean | false | プレビュードキュメントの html/body を高さ100%まで広げる。高さ自動調整と干渉するため、必ず明示的な height と併用する |
sandbox | string | auto | iframe の sandbox 属性。省略時は計算済みのデフォルト(スクリプトありなら allow-scripts allow-same-origin、なしなら allow-same-origin)。信頼できないコンテンツにはより厳しい値を指定 — ただし allow-same-origin を外すと高さ自動調整が無効になるため height も併せて指定する |
externalStyles | string[] | undefined | 外部スタイルシート URL。head/css より前に <link rel="stylesheet"> として挿入される。コンポーネント単位のみ — ビルドバンドルされず、表示時にクライアントサイドで読み込まれる |
externalScripts | string[] | undefined | 外部スクリプト URL。<script src> として挿入される。js と同様にサンドボックス/syncDelay の導出を切り替える。コンポーネント単位のみ — ビルドバンドルされず、表示時にクライアントサイドで読み込まれる |
preflight | boolean | true | false を指定すると、注入される preflight リセットをスキップする — externalStyles/externalScripts で読み込む独自リセットを持つフレームワーク向け |
showResources | boolean | false | externalStyles/externalScripts を「HTML」コードパネルの先頭に生の行として表示する。デフォルトではパネルから除外される |
シンタックスハイライトと遅延 WASM
ソースコードパネルは公開されている @takazudo/zfb-md-wasm のパッケージルートを遅延インポートし、次の言語をセマンティックハイライターで処理します:
html— HTML パネルおよび Head パネルcss— CSS パネルjavascript— JS パネル
レンダラーは安全にエスケープされた pre.hi-root / hi-* マークアップを出力し、ドキュメントフェンスと同じ --zd-syntax-* パレットを共有します。遅延読み込みの境界はパネルを開く操作です。それより前に、生成された JavaScript glue と WASM companion リソースがリクエストされることはありません。未知の言語に対する warning は、エスケープ済みのセマンティックフォールバックマークアップを使用します。インポート、初期化、不正なオプション、現在の呼び出しの失敗時には、JSX でエスケープされたプレーンな <pre><code> フォールバックを維持します。一時的なインポート失敗は、後続のパネル描画で再試行できます。
独自の配信基盤で本番出力を提供する場合は、生成された .mjs / .wasm アセットを保持し、JavaScript と application/wasm の正しい MIME type で配信してください。パッケージ内部の glue パスを手作業でコピーしないでください。リソースグラフは zfb のビルドが管理します。
このブラウザ実行時の言語セットは、通常のビルド時コードブロックで利用できる言語一覧より限定されています。
注意事項
プレビューは CSS リセット(Tailwind v4 preflight)を含む分離された
<iframe>内で描画されるため、スタイルが外部に漏れることはありません。プレビューはデフォルトで
sandbox="allow-same-origin"(jsプロップまたは<script>がある場合はsandbox="allow-scripts allow-same-origin")を使用し、contentDocument経由で iframe の高さを自動同期します。srcdocの内容は作成者が管理する MDX です。信頼できないコンテンツにはsandboxプロップで上書きしてください — 上記のセキュリティとsandboxプロップを参照。htmlPreview設定フィールドのグローバルリソースは、コンポーネント単位のプロップの前に挿入されます。html、css、jsプロップはインデント付きのテンプレートリテラルに対応しています。先頭の空白はソースコード表示時に自動的に除去されます。クライアントサイドのハイドレーションはコンポーネントラッパーにより自動的に処理されるため、MDX 内で
client:loadディレクティブを付ける必要はありません。externalStyles/externalScriptsは表示時にクライアントサイドで読み込まれます — プレビュー iframe が描画されるときにブラウザが行うネットワークリクエストであり、ビルド時にバンドルされるアセットではありません。上記の外部スタイルシートとスクリプトを参照。srcdoc への挿入順序: preflight リセット(
preflight={false}でない限り)→fullHeightスタイル →externalStyles→head→css。