トースト
トーストは、画面の隅に現れる短い時間制限つきの通知です。
installToast ビヘイビアが document.body 上の hc:toast イベントを
待ち受け、ページのトースト領域へトーストを描画し、数秒後に自動で
解散させます。
各ボタンはデモエンドポイントに POST し、サーバは 204 No Content と
HX-Trigger: {"hc:toast":…} ヘッダーを返します — htmx が <body> 上で
イベントを発火し、installToast がトーストを描画します。下のクライアント
発火のプレビューと違い、こちらは実際のエンドポイントを往復します —
サーバ応答契約をそのまま実装したデモで、api/recipes/toast/ 配下に
置かれています。Sticky error は duration: 0 なので、閉じるまで残ります —
すべてのトーストは閉じるボタンを描画し、フォーカス中のトーストは
Escape でも閉じられます。
マークアップ
Section titled “マークアップ”トースト領域は単一のホスト要素です。<body> の終わり近くに一度だけ
置いてください。領域がなければ、ビヘイビアが自動で作成します。
<div class="hc-toast-region" data-hc-toast-region role="region" aria-label="Notifications"></div>トーストの発火
Section titled “トーストの発火”クライアントから
Section titled “クライアントから”detail オブジェクトつきのバブリングする hc:toast イベントを発火
します:
document.body.dispatchEvent( new CustomEvent('hc:toast', { bubbles: true, detail: { message: 'Saved', variant: 'success' }, }));試してみてください — 各ボタンが上のイベントを発火します。トーストは ページの隅に現れ(そして自動で消えます):
// installToast() must be installed (it is in the behaviors bundle).saveButton.addEventListener('click', () => { document.body.dispatchEvent(new CustomEvent('hc:toast', { bubbles: true, detail: { title: 'Saved', message: 'Changes saved.', variant: 'success' }, }));});サーバから(htmx)
Section titled “サーバから(htmx)”HX-Trigger レスポンスヘッダーを返します。htmx が body 上で
hc:toast を発火してくれます。
HTTP/1.1 200 OKHX-Trigger: {"hc:toast":{"message":"Saved","variant":"success"}}1 つのレスポンスに複数イベントを載せる場合:
HX-Trigger: {"hc:toast":{"message":"Saved","variant":"success"}, "items:refresh":true}detail の形
Section titled “detail の形”| フィールド | 型 | デフォルト | 備考 |
|---|---|---|---|
message | string | (必須) | 本文テキスト。 |
title | string | (省略) | メッセージの上の太字 1 行。 |
variant | string | 'info' | info / success / warning / error。 |
duration | number | 4500 | ミリ秒。0 は手動で消されるまで保持。 |
id | string | (省略) | 安定ハンドル: 同じ id の後続 hc:toast は新規に積まず、既存トーストをその場で更新します。 |
action | object | (省略) | { label, event } — アクションボタンを描画。押下で detail: { id, action, toast } を持つバブリング CustomEvent(event) を発火し、トーストを閉じます。 |
variant="error" はトーストを role="alert" /
aria-live="assertive" にも切り替えるため、スクリーンリーダーは割り込ん
で読み上げます。他のバリアントは role="status" /
aria-live="polite" を使います。
アクションボタンと id による更新
Section titled “アクションボタンと id による更新”id と action を組み合わせると、他のレシピが依拠する 2 つの
サーバー駆動パターンになります:
- id による更新(loading → success / error): まず
{ id: 'job-42', message: 'Exporting…', duration: 0 }を送り、次に 同じidでhc:toastを送ると、表示中のトーストがその場で 変化します(トースト → id による更新の プロミストーストパターン)。 - アクション(例: 元に戻す):
{ action: { label: 'Undo', event: 'hc:undo' } }でボタンが描画され、htmx はdata-hx-trigger="hc:undo from:body"で 受け取れます — undo-delete レシピを 参照。すべてのトーストには閉じるボタン(.hc-toast__close)も 描画されるため、スティッキートースト(duration: 0)はactionが なくてもポインタで解散できます。フォーカスを含むトーストは Escape で解散できます(アクションのイベントは発火しません)。
// Successdocument.body.dispatchEvent(new CustomEvent('hc:toast', { bubbles: true, detail: { message: 'Invoice sent.' },}));
// Error, sticky until dismisseddocument.body.dispatchEvent(new CustomEvent('hc:toast', { bubbles: true, detail: { title: 'Sync failed', message: 'Could not reach the server. Retrying…', variant: 'error', duration: 0, },}));サーバサイドのハンドラから:
# Djangofrom django.http import HttpResponseimport json
def delete_item(request, id): item = get_object_or_404(Item, pk=id) item.delete() return HttpResponse('', headers={ 'HX-Trigger': json.dumps({ 'hc:toast': {'message': 'Deleted.', 'variant': 'success'}, }), })ワイヤ契約はボディのフラグメントではなくレスポンスヘッダーです:
htmx が処理するどのレスポンスも HX-Trigger: {"hc:toast":{…}} を
運ぶことができ、htmx が <body> 上で hc:toast イベントを発火
します — ペイロードのスキーマは上の detail の形です。
| ケース | レスポンス |
|---|---|
| トーストのみ — ページ上は何も変わらない | 204 No Content + HX-Trigger: {"hc:toast":{"message":"Saved","variant":"success"}}(ライブデモの形) |
| スワップと一緒に | 任意の 2xx フラグメントレスポンス + 同じヘッダー — トーストはスワップに同乗します |
| 1 レスポンスに複数イベント | 1 つの JSON オブジェクト: HX-Trigger: {"hc:toast":{…},"items:refresh":true} |
| 失敗の通知 | 非 2xx + HX-Trigger のエラートースト — htmx は何もスワップせず、トーストが失敗を報告します(live-search や datagrid-pager の失敗時の作法) |
ヘッダーの値は latin-1 です — 非 ASCII のテキストは JSON の \uXXXX に
エスケープしてください(htmx はネイティブにパースします。
ワンライナーは
undo-delete の契約に
あります)。
アクセシビリティ
Section titled “アクセシビリティ”info/success/warningはrole="status"(polite)を使う ため、ユーザーの流れを遮りません。errorはrole="alert"(assertive)を使い、失敗を即座に読み上げ させます。本物のエラーのために取っておいてください。- 領域自体はラベルつきの
regionランドマークです — 支援技術で移動 できます。 - トーストは自動で消えます。ユーザーが対応しなければならない重要な 情報をここに置かないでください。完了したアクションの確認が正準の ユースケースです。
プログレッシブエンハンスメント
Section titled “プログレッシブエンハンスメント”hc.behaviors.js なしでは、hc:toast イベントは発火されてもリスナーが
存在せず、何も描画されません。HTTP レスポンス自体は依然として妥当です —
HX-Trigger は素の fetch() 呼び出しには no-op です。
JavaScript なしで確認を伝えなければならないアプリケーションでは、
フラッシュメッセージをページ内にサーバレンダリングし
(hc-alert が正しい
コンポーネントです)、次のレスポンスで取り除いてください。