alpinejs-django について
alpinejs-django は、Django が描画するテンプレートで Alpine.js によるブラウザー側の操作を実装するためのスキルです。Alpine、Django、HTMX、JavaScript の役割分担に加え、セットアップ、アクセシビリティ、セキュリティ、検証を案内します。
主な機能
- 01Django のアセットで Alpine を設定
- 02一時的な状態を Alpine で管理
- 03永続化と検証を Django に任せる
- 04HTMX でサーバー更新を連携
- 05アクセシビリティと CSP の指針
- 06テンプレートと操作を検証
活用シーン
- 01テンプレートにドロップダウン、タブ、モーダルを追加
- 02クライアント側のフィルターや読み込み状態を実装
- 03HTMX で画面断片を更新し UI 状態を維持
- 04Alpine の変更をアクセシビリティと安全性の観点で確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lvtd-llc/ skills --skill alpinejs-djangoインストール後、Claude Code で/alpinejs-djangoを入力して読み込まれたか確認します。
詳細
Django での Alpine.js
Django がレンダリングするテンプレートで、ドロップダウン、モーダル、タブ、開閉パネル、インラインフィルター、無効化/読み込み中の状態、小規模なプレビューの操作、クライアント側のみの切り替えなど、ブラウザー内の状態を扱う場合にこのスキルを使用します。永続化が必要な状態の信頼できる情報源には、Django のビュー、フォーム、モデルを使用します。サーバーから最新の HTML を返す必要がある場合は、HTMX を使用します。
セットアップの確認
- プロジェクトで Alpine をどのように読み込んでいるかを確認します。信頼できる情報源として、既存の静的アセットまたはバンドルのパイプラインを優先します。
- HTMX、Alpine、アプリの JavaScript を読み込むベーステンプレート、レイアウト、またはバンドルのエントリーポイントを確認します。初期化の方法を意図的に変更する場合を除き、現在の読み込み順序を維持します。
- 読み込まれる Alpine ファイルが自動起動するものか、モジュールベースかを確認します。プロジェクトですでに自動起動する Alpine ビルドを読み込んでいる場合は、
Alpine.start()を呼び出さないでください。モジュールビルドを使用する場合は、所有するエントリーポイントからコンポーネントを登録し、Alpine を起動します。 - シンプルな Alpine の動作は、通常、
x-dataを使って Django テンプレート内に記述します。 - 再利用可能なコンポーネントやストアを切り出す価値がある場合は、Alpine の起動前に登録します。アプリ全体のスクリプトから
document.addEventListener("alpine:init", ...)を利用する前に、既存のスクリプトの読み込み順序を確認します。 - 再利用可能な Alpine の登録が必要な場合は、Alpine の起動前に実行されるスクリプトまたはエントリーポイントを追加するか、既存のものを再利用します。
document.addEventListener("alpine:init", ...)内でコンポーネントとストアを登録し、プロジェクトで通常使用しているアセットのパスを通じてファイルを読み込み、Alpine を二重に起動しないようにします。
責務の分担
- Django は永続化、認可、検証、リダイレクト、レンダリング済み HTML を担当します。
- HTMX はサーバーとの往復通信と DOM の置き換えを担当します。
- Alpine は、すでにブラウザー内にある一時的な状態を担当します。
- 1 つの Alpine コンポーネントに自然にスコープされない、共有 DOM の動作は、プレーンな JavaScript モジュールまたはバンドルのエントリーポイントが担当します。
- 同じ動作を Alpine とプレーンな JavaScript モジュールの両方で重複して実装しないでください。
テンプレートのパターン
制御するマークアップの近くに、小さな x-data オブジェクトを配置します。
<div
x-data="{ open: false }"
@keydown.escape.window="open = false"
@click.outside="open = false"
>
<button
type="button"
:aria-expanded="open.toString()"
@click.stop="open = !open"
>
Menu
</button>
<div x-cloak x-show="open" x-transition>
...
</div>
</div>
手動での DOM 操作ではなく、Alpine のディレクティブを優先します。
- 要素を DOM に残したまま表示を切り替えるには、
x-showを使用します。 - 要素を生成したり破棄したりするには、
<template>上でx-ifを使用します。 - クライアント側のみの入力状態には
x-modelを使用します。Django のフォーム送信と検証は引き続きサーバーで行われます。 - 状態に応じて属性を設定するには、
:class、:disabled、:aria-expanded、:hiddenを使用します。 - 1 つの名前付き状態遷移には
$watchを使用します。依存関係が単純で意図が明確な場合に限り、x-effectを使用します。 - Alpine コンポーネント間、または Alpine から HTMX のトリガーへのブラウザーイベントには、
$dispatchを使用します。
デフォルトで非表示にする要素には x-cloak を使用します。ベース CSS に必須の [x-cloak] { display: none !important; } ルールが含まれていることを確認してください。
Django のデータ
可能な限り、複雑な JavaScript 式の中で Django の補間を使わないようにします。
単純な値には、HTML 属性を優先します。
<div
data-initial-label="{{ object.name }}"
x-data="{ label: '' }"
x-init="label = $el.dataset.initialLabel"
>
<span x-text="label"></span>
</div>
構造化された値には、Django の json_script を優先し、x-init で解析します。
{{ rows|json_script:"rows-data" }}
<div
x-data="{ rows: [] }"
x-init="rows = JSON.parse(document.getElementById('rows-data').textContent)"
>
<template x-for="row in rows" :key="row.id">
<span x-text="row.name"></span>
</template>
</div>
Alpine の式の中で |safe を使用しないでください。ブラウザーにテキストを表示する必要がある場合は、x-text を使用します。x-html は、信頼でき、すでにサニタイズ済みの HTML に限って使用します。ほとんどの HTML は Django でレンダリングするか、HTMX 経由で返すようにしてください。
Alpine と HTMX
HTMX が x-data を含むフラグメントを置き換えると、Alpine は新しいコンポーネントを自動的に初期化します。HTMX の置き換え後に Alpine を再起動しないでください。
置き換え対象となる HTMX のターゲットの外に、Alpine の永続的な状態を保持します。
<section x-data="{ panelOpen: false }">
<button type="button" @click="panelOpen = !panelOpen">Filters</button>
<div id="results" hx-get="{% url 'search_results' %}" hx-trigger="change from:#filters">
...
</div>
</section>
HTMX のレスポンスと Alpine の状態との境界には、イベントを使用します。Django から HX-Trigger または HX-Trigger-After-Swap レスポンスヘッダーを設定し、Alpine 側でリッスンします。
<div x-data="{ open: true }" @profile-saved.window="open = false">
<form hx-post="{% url 'profile_update' %}" hx-target="#profile-panel" hx-swap="outerHTML">
...
</form>
</div>
HTML 属性では大文字と小文字が区別されないため、Alpine から HTMX のライフサイクルイベントをリッスンする場合は、@htmx:after-swap.window のようにケバブケースを使用します。
Alpine がディスパッチするイベントに HTMX が反応する場合は、トリガーを明示します。
<button type="button" x-data @click="$dispatch('refresh-results')">
Refresh
</button>
<div hx-get="{% url 'results' %}" hx-trigger="refresh-results from:body">
...
</div>
アクセシビリティ
- フォームを送信する場合を除き、実際のボタンには
<button type="button">を使ってください。 - Alpine の状態を ARIA の状態にバインドしてください。特に、
aria-expanded、aria-controls、aria-selected、aria-hiddenが対象です。 - 閉じられるオーバーレイでは、
@keydown.escape.windowをサポートしてください。 - ポップオーバーやメニューでは、表示可能なトリガーと組み合わせて
@click.outsideを使ってください。 - モーダル、メニュー、HTMX で差し替えられるコンテンツのフォーカス動作を維持してください。フォーカストラップが必要な場合は、属性だけで脆弱なトラップを独自に実装するのではなく、意図的にフォーカスを絞ったプレーンな JS モジュールまたは Alpine プラグインを追加してください。
セキュリティと CSP
- すべての Alpine 式は、ユーザーのブラウザーで実行される JavaScript として扱ってください。
- ユーザーに見せる権限のないシークレット、署名済みトークン、特権データを
x-data、data-*、json_script、非表示の入力欄に含めないでください。 unsafe-evalを使わない厳格な Content Security Policy が必要な場合は、意図的に Alpine の CSP ビルドに切り替え、Alpine 式を再テストしてください。デフォルトのalpinejs/dist/cdn.min.jsビルドは CSP ビルドではありません。- Alpine コードで
fetch()リクエストを行う場合は、Django CSRF ヘッダーを含めるか、既存の HTMX/Django フォームを使ってください。
検証
- テンプレートのみの Alpine の変更では、そのページを対象とする Django テンプレートまたはビューのテストを実行し、JavaScript モジュールを変更した場合は
npm run lintも実行してください。 - HTMX の操作については、ページ全体と部分レスポンスの両方の経路をテストしてください。
- プロジェクトにフロントエンドのビルド手順がある場合は、静的出力を信頼する前に実行してください。
- 表示される UI の動作を変更する場合は、状態を持つコントロールをライトモードとダークモードで手動確認してください。