Alpine.jsでdialogタグを制御する方法

こんにちは。エキサイトでデザイナーをしている齋藤です。

エキサイトホールディングス Advent Calendar 2024 シリーズ1の9日目を担当します。

qiita.com

今回はAlpine.jsでdialogタグを制御する方法をご紹介します。

dialogタグとは

dialogタグはHTML標準のダイアログボックス要素です。2022年3月にFirefoxでもサポートされ、広く使用できるようになりました。

HTML標準ということで、表示されたダイアログは自動的に最上位のレイヤーに移動するためz-indexの調整が不要であったり、escキーで閉じられたりと多くのメリットがあります。

一方で制御にはJavaScriptが必要です。

See the Pen Untitled by AyumuSaito (@ayumusaito-excite) on CodePen.

<button id="show-btn" type="button">ダイアログを表示</button>

<dialog id="dialog">
  <p>ダイアログです</p>
  <button id="close-btn" type="button">閉じる</button>
</dialog>

<script>
  const showTriggerBtn = document.getElementById("show-btn");
  const closeTriggerBtn = document.getElementById("close-btn");
  const dialog = document.getElementById("dialog");

  showTriggerBtn.addEventListener("click", () => {
    dialog.showModal();
  });

  closeTriggerBtn.addEventListener("click", () => {
    dialog.close();
  });
</script>

Alpine.jsで制御する

Alpine.jsを使用して制御すると以下のようになります。

See the Pen Untitled by AyumuSaito (@ayumusaito-excite) on CodePen.

<div x-data>
  <button @click="$refs.dialog.showModal()" type="button">ダイアログを表示</button>

  <dialog x-ref="dialog">
    <p>ダイアログです</p>
    <button @click="$refs.dialog.close()" type="button">閉じる</button>
  </dialog>
</div>

$refsを使用してdialogタグのDOMノードにアクセスしてshowModal()close()を実行しています。

$refsについては以下の記事も合わせてご覧ください。

tech.excite.co.jp

コンテンツの外側を押下しても閉じられるようにする

先の例では「閉じる」ボタンを押下しないと非表示にできませんが、コンテンツの外側を押下しても非表示にできるようにすると操作性が向上します。

外側(赤い部分)を押下しても非表示にできるようにする

See the Pen Alpine.jsでdialogを制御(外側押下でも非表示に) by AyumuSaito (@ayumusaito-excite) on CodePen.

<div x-data>
  <button @click="$refs.dialog.showModal()" type="button">ダイアログを表示</button>

  <dialog @click.self="$refs.dialog.close()" x-ref="dialog">
    <!-- ダイアログのスタイルは.dialog-contentに当てる -->
    <div class="dialog-content">
      <p>ダイアログです</p>
      <button @click="$refs.dialog.close()" type="button">閉じる</button>
    </dialog>
    </div>
</div>

まず、dialogタグに@click.self="$refs.dialog.close()"を付与して、自タグが押下された場合にclose()が実行されるようにします。

このままですと、コンテンツの部分(今回の場合は文章と「閉じる」ボタン)を押下しても非表示になってしまいます。

そこで、コンテンツの部分をwrapすることで@click.selfによる自タグのクリック判定から除外させ、dialogタグがshowModal()のときに背後に挿入される疑似要素(::backdrop)の押下のみが判定されるようにします。

まとめ

今回はAlpine.jsでdialogタグを制御する方法をご紹介しました。

通常の方法では、HTMLとJSが分離するためどの要素に対する処理なのかが一見分かりづらかったり、他要素への影響に気を使う必要がありました。

一方でAlpine.jsでは、HTMLの属性としてJSの処理を記述するため要素との関係性も分かりやすく、x-data単位でスコープされるため他要素への影響も気にせずに実装ができるようになりました。

ぜひ、dialogタグとAlpine.jsの組み合わせをお試しいただければと思います。

ご精読ありがとうございました。