コンテンツにスキップ

ドロワー

hc-drawer は、ネイティブの <dialog> 要素を、ビューポートの任意の 端からスライドインするパネルとしてスタイルします。ネイティブの ダイアログがフォーカストラップ、Escape で閉じる、::backdrop レイヤーを無料で処理します。HC は端への配置、スライドイン / アウトの アニメーション、そして(installDrawer 経由で)スライドパネルに ユーザーが期待するバックドロップクリックで閉じる操作を足します。

別名: サイドパネル、オフキャンバス、シート。

プリミティブ必要バージョン
HTML <dialog> + showModal()すべてのエバーグリーンブラウザ
CSS @starting-style + transition-behavior: allow-discreteChrome 117+、Firefox 129+、Safari 17.5+

スライドアニメーションは穏やかにデグレードします — @starting-style のない古いブラウザでは入場トランジションなしで 最終位置にスナップしますが、ドロワーは機能します。

Settings

Form fields, settings, anything.

import { installDrawer } from '@hypermedia-components/core';
installDrawer();

installDrawer() は冪等で、アンインストーラを返します。ゼロ設定の @hypermedia-components/core/behaviors エントリが自動インストールし、 htmx でスワップされた内容も自動で拾います。

data-sideright(デフォルト)、lefttopbottom を 受け付けます。右 / 左のドロワーはビューポートの高さを満たし、幅を --hc-drawer-side-max-width で制限します。上 / 下のドロワーは ビューポートの幅を満たし、高さを --hc-drawer-vert-max-height で 制限します。

Left drawer

Slides in from the left edge.

Top drawer

Slides in from the top edge.

Bottom drawer

Slides in from the bottom edge.

推奨順に 3 つの慣用パターン:

method="dialog" のフォーム内のボタンは、送信でダイアログを閉じ ます。ネイティブ、アクセシブル、宣言的です。

<form method="dialog">
<button class="hc-button" type="submit">Cancel</button>
</form>

バックドロップクリック(installDrawer が追加)

Section titled “バックドロップクリック(installDrawer が追加)”

ドロワーパネルの外側(::backdrop 領域)のクリックがダイアログを 閉じます。ビヘイビアは event.target === dialog でこれを検知します。

ドラッグで解散(installDrawer が追加)

Section titled “ドラッグで解散(installDrawer が追加)”

パネルをアンカーされた端の方向へドラッグすると解散します。軸は data-side に従います(right / left → 水平、top / bottom → 垂直)。 パネルサイズの約 40% を超えるか、素早いフリックで、ドロワーは スライドアウトして閉じます — そこに届かず放すとスナップバックします。 動くのは外向きだけです(内向きのドラッグはクランプされるため、 ラバーバンディングはなく、prefers-reduced-motion の特別扱いも 不要です)。

ジェスチャはパネルのクローム — __header / __footer — から つかみます。スクロール可能な __body やインタラクティブな コントロールからは決してつかまないため、コンテンツのスクロールと ボタンは機能し続けます。Pointer Events ベースなので、マウス、タッチ、 ペンで機能します。

document.getElementById('settings-drawer').close();

htmx のレスポンスハンドラから使うのに便利です — htmx 成功時に ダイアログを閉じるパターンには installCloseDialogと 組み合わせてください。

サーバ取得に応じてドロワーを開き、htmx にコンテンツをスワップさせ ます:

<button class="hc-button"
data-hx-get="/users/42/edit"
data-hx-target="#user-drawer .hc-drawer__body"
data-hx-swap="innerHTML"
onclick="document.getElementById('user-drawer').showModal()">
Edit user
</button>
<dialog class="hc-drawer" id="user-drawer" data-side="right">
<header class="hc-drawer__header">
<h2 class="hc-drawer__title">Edit user</h2>
<form method="dialog">
<button class="hc-button" data-variant="ghost" data-size="sm"
type="submit" aria-label="Close">×</button>
</form>
</header>
<div class="hc-drawer__body">
<span class="hc-spinner" role="status" aria-label="Loading"></span>
</div>
</dialog>

フォーム保存後の成功時クローズには:

<form
data-hx-post="/users/42"
data-hx-target="this"
data-hc-close-dialog-on-success>
</form>

同梱の installCloseDialog ビヘイビアが、成功した htmx レスポンスで 内包する <dialog> を閉じます。hc-dialog と同じパターンです。

  • ネイティブの <dialog> はすでに正しい role、フォーカストラップ、 Escape のセマンティクスを公開しています。role="dialog"aria-modal="true" を足さないでください — 冗長で、一部の スクリーンリーダーを混乱させえます。
  • フォーカストラップの着地先があるよう、ドロワー内には常に フォーカス可能な要素を含めてください。ヘッダーの閉じるボタンか フッターの主アクションで十分です。
  • 見える閉じる操作部を用意してください。上の <form method="dialog"> パターンは、見える「×」ボタンに組み込みの キーボード起動経路(ボタン上の Enter / Space)を対にしています。
  • スライドアニメーションは prefers-reduced-motion: reduce を尊重 します — ユーザーがオプトアウトしていればトランジション時間は 0 ms に落ちます。

ドロワーは意図的に 1 つの見た目だけを提供します — 面は hc-dialog と 同じ規約に従うため、同じテーマトークン(ライト / ダーク / カラー)が そのまま機能します。破壊的フロー向けの data-variant="error" の ようなバリアントは、コンテナのクロームではなくコンテンツ(赤い ヘッダー、先頭のエラーアラート)でモデル化してください。

component トークン(component.tokens.json):

トークンパス用途
drawer.bg / fg / border面の色。
drawer.side-max-width右 / 左ドロワーの幅の上限。
drawer.vert-max-height上 / 下ドロワーの高さの上限。
drawer.paddingヘッダー / ボディ / フッターの内側パディング。
drawer.gapヘッダー / フッターのフレックスギャップ。
drawer.backdrop::backdrop の背景。
drawer.durationスライドアニメーションの時間。
生成される CSS 変数を表示
--hc-drawer-bg | -fg | -border
--hc-drawer-side-max-width | -vert-max-height
--hc-drawer-padding | -gap
--hc-drawer-backdrop | -duration