RACCOON TECH BLOG

株式会社ラクーンホールディングスのエンジニア/デザイナーから技術情報をはじめ、世の中のためになることや社内のことなどを発信してます。

dialogタグでセマンティックにモーダルを作成するには

デザイン戦略部塚原です。
新しく追加されたdialogタグの特徴に触れつつ弊社のサイトで使われているモーダルをつくってみます。

対応ブラウザ

執筆時のSafariバージョンが16.xxのため、気になるのはSafariくらいでしょうか。

ブラウザ バージョン
Safari 15.4
Safari ios 15.4
Chrome 37
Firefox 98

どこで使うべき?

その名前が示す通りダイアログボックスを表示したい時に使います。
小さなウィンドウが開き、自由に開閉ができるものや、ユーザーに何らかの操作をさせるためのモーダル等で使えます。
今まではdivタグでマークアップしていた方も多いと思いますが、dialogタグを使う事により、ソースを見るだけで意図が理解できるので積極的に使いたいですね。

ダイアログボックスとは
https://wa3.i-3-i.info/word11408.html

dialogタグを使うべきではないところ

ツールチップ、ドロップダウンメニューなど

許可されている子要素

dl、ul、pタグ等のフローコンテンツに属するHTMLタグ
※フローコンテンツのタグはこちらから
https://developer.mozilla.org/ja/docs/Web/HTML/Content_categories#%E3%83%95%E3%83%AD%E3%83%BC%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84

基本コード

下記で閉じた状態のダイアログが作成できます。
こちらにダイアログ内容や、イベント処理を追加していきます。

<dialog>
  <button type="button">閉じるボタン</button>
</dialog>
<button type="button">トリガーとなるボタン</button>

関連する機能

HTMLだけでは開閉式の処理はできないのでdialogタグを操作するために用意されている下記メソッド3点を使って、javaScriptで書いていきます。

メソッド

・close()
・showModal()
・show()
今までは閉じるボタンをクリックしたらモーダル要素をdisplay:noneにする等、CSSの操作をしていましたが、これらを使えばよりシンプルに実装ができそうです。

close()

close()は2つの使い方があります。

1.dialogタグを閉じる処理
addEventListenerを使って、閉じるボタンをクリックしたらcloseが発火するように記載します。
これでモーダルが非表示になります。

HTMLDialogElement.close()

2.値の受け渡し(文字列の引数を設定できる)
例として、dialog要素内のセレクトボックスの選択値をモーダル外に渡す事ができます。

close(returnValue)    

完成図

サンプルコード

  <div>
    結果:<span id="result"></span>
  </div>
  <dialog id="modal" class="modal">
    <div class="modal-inner">
      <p class="modal-heading">モーダル見出し<button type="button" class="closeButton" id="closeButton">✕</button></p>
      <div class="modal-container">
      <select name="animal" id="animal">
        <option value="rabbit">rabbit</option>
        <option value="fox">fox</option>
        <option value="elephant">elephant</option>
      </select>
      </div>
    </div>
  </dialog>
  <button id="modalOpen">ボタン</button>
 <script>
      const modal = document.getElementById("modal");
      document.getElementById("closeButton").addEventListener("click",function() {
        const selected = document.getElementById("animal").value;
        modal.close(selected) //閉じるときに、渡したい値を設定
      })

      modal.addEventListener("close",function(){
        const text = modal.returnValue //returnValueでdialogタグの戻り値を取得できる
        document.getElementById("result").innerHTML = text 
      })    

標準では、閉じるために押したボタンの値を返すようになっています。
※buttonに設定したvalue値。
その場合は引数設定はなしで、modal.close()と記載するだけでボタンのvalue値を渡す事ができます。

showModal() vs show()

dialogタグの要素を表示し、open属性が付与されます。
文字だけ見ると一見同じ機能を持つように見えるので、2つ併せて説明します。

HTMLDialogElement.showModal()
HTMLDialogElement.show()

showModal()
背景を覆うマスクが::backdropで付与され、背景の操作ができなくなります。
ページ内にz-indexの高い他要素が存在していたとしても、対象のdialogタグが最上位に表示されます。
そのため、一般的なモーダルを作成する場合はこちらのメソッドを使う事が多いでしょう。

show()
背景を覆うマスクは表示されず、背景の操作ができます。
ページ内にz-indexの高い絶対配置の要素が存在している場合それらが優先されます。
このときのdialogタグに標準で指定されているCSSには、
position:absolute
margin:auto
があるため中央配置にはなりますが、absoluteで高さを持たないので該当のdialogタグより下に書かれている要素が食い込んできます。

サンプル(show())

弊社サイトの場合、
show()は、そこまで主張する必要がない下記のような操作ポップに使えそうだなと考えています。
これは設定変更フォームでデータを修正し、変更が完了となったらこのポップが出ます。
非表示にするには一度ユーザーが✕ボタンをクリックする必要があります。

属性

・open
イベントによってdialogタグを表示させる場合はこの属性を記載しておく必要はありません。
しかし、デフォルトでdialogタグ要素を表示させておきたい場合は、dialogタグにopenと記載する必要があります。
dialogタグが表示されたらopen属性が付与され(showModal()/show()が発火)、
非表示になると削除されます(close()が発火)。
ブラウザ毎に定義されているCSSで、dialog[open]時にdisplay:blockが設定されています。

dialogタグで作成した要素の特徴

・dialog要素の高さが指定の高さを超える場合、スクロールが発生する
・Escキーで閉じる
→Escキーは処理をキャンセルしたい時に、またはダイアログボックスやドロップダウンメニューを閉じる役割をもっています。
divタグ等で自作モーダルを作成していた時にはEscの処理を書いていた方も多いと思います。
キーボードユーザーのフォローも考慮するとdialogタグはとても便利ですね。

実際にdialogタグでモーダルつくってみると...

今回はボタンをクリックしたらモーダルが開くという一般的なものを作成してみました。
閉じるトリガーは、モーダル内の×ボタンまたは背景マスク部分としています。
背景マスク部分をクリックしたときに閉じる必要がなければjavaScriptの記述がもっとシンプルになります。
デザインは弊社のサイトで使っているモーダルを再現している為、黒帯見出しがついていますがcssの調整次第で汎用的なモーダルを作成することが出来ます。

完成図

サンプルコード

  <dialog id="modal" class="modal">
    <div class="modal-inner">
      <p class="modal-heading">モーダル見出し<button type="button" class="closeButton">✕</button></p>
      <div class="modal-container">
      <p>テキスト</p>
      </div>
    </div>
  </dialog>
  <button id="modalOpen">ボタン</button>
  <style>
    p {
      margin: 0;
    }
    .modal {
      border: none;
      padding: 0;
      background: none;
    }
    .modal:modal {
      width: 90%;
      max-width: 700px;
      max-height: 700px;     
    }
    .closeButton {
      position: absolute;
      right: 10px;
      top: 50%;
      margin-top: -16px;
      border-radius: 50%;
      line-height: 1;
      width: 30px;
      height: 30px;
      background-color: #ffffff;
      border: 1px solid #4d4d4d;
    }
    .modal-heading {
      position: relative;
      background: #4d4d4d;
      padding: 11px 15px;
      font-weight: bold;
      margin: 0;
      color: #fff;
    }
    .modal-inner {
      background: #fff;
    }
    .modal-container {
      padding: 20px;
      padding: 20px;
    }
  </style>
  <script>
  const modal = document.getElementById("modal")
  const button = document.getElementById("modalOpen")
  button.addEventListener("click",function(){
    modal.showModal()
  })
  modal.addEventListener("click",function(el){
    const target = el.target
    //✕ボタンまたはモーダル外(黒背景)をクリックしたら、モーダルを閉じる
    if("closeButton".includes(target.className) || target.closest(".modal-inner") == null) {
      modal.close()
    }
  })  
  </script>

スクロールについて補足

.modal-containerの高さがある場合、
dialogタグにはoverflow:autoが標準設定がされているため、見出し部分までスクロールバーがかかってしまいます。
そのため、全体がスクロールしないようにCSSで追記をして、コンテンツ内のみスクロールバーがかかるよう修正します。(以下に修正分のCSS記載)

完成図

サンプルコード

.modal:modal{
  overflow: hidden;
}
.modal-container{
  overflow: auto;
  max-height: 600px;  
}

まとめ

今までよりも簡単に、モーダルが持つ機能の実装・またセマンティックにマークアップできるdialogタグが、各ブラウザで使用できるようになりました。
プラグインでモーダルを導入しているサイトも多いと思いますので、警告ダイアログなど小さい所からdialogを試してみるのもよさそうですね。

ラクーングループは一緒に働く仲間を絶賛大募集中です!
フロントからバック、はたまた企画に要件定義など幅広く経験できる環境です。もしご興味を持っていただけましたら、こちらからエントリーお待ちしています!

一緒にラクーンのサービスを作りませんか? 採用情報を詳しく見る

関連記事

運営会社:株式会社ラクーンホールディングス(c)2000 RACCOON HOLDINGS, Inc