dialog要素とtemplate要素を使用してモーダルウィンドウを作る

  • Updated: 2023.08.08
  • Published: 2023.07.29
  • 691views
  • HTML
  • JavaScript

概要

dialog要素でモーダルを表示しつつ、template要素で表示する内容を切り替えるモーダルウィンドを作成します。


サンプル


ソース

HTML

<div>
  <button class="showDialog" data-id="template1">template1</button>
</div>
<div>
  <button class="showDialog" data-id="template2">template2</button>
</div>
<div>
  <button class="showDialog" data-id="template3">template3</button>
</div>

<dialog id="favDialog">
  <form>
    <div class="content-wrap">
      <button value="cancel" formmethod="dialog" class="btn-close"></button>
      <div class="content-main"></div>
      <div class="btns">
        <button value="cancel" formmethod="dialog">Close</button>
      </div>
    </div>
  </form>
</dialog>

<template id="template1">
  <div>
    template1
  </div>
</template>
<template id="template2">
  <div>
    template2
  </div>
</template>
<template id="template3">
  <div>
    template3
  </div>
</template>

dialogの中をformで囲っています。buttonformmethod="dialog"を指定することによってモーダルウィンドウを閉じることができます。

templateはIDを振って表示させたいコンテンツ内容をコーディングしています。

表示元のボタンに設定したdata-id="template1"template id="template1"template1(ユニークな値)合わせることによってモーダルウィンドウの内容を出し分けます。


CSS

#favDialog{
    width: 100%;
    max-width: 100%;
    max-height: 100%;
    border: none;
    background-color: transparent;
    position: fixed;
    z-index:1000;
    left: 0;
    top: 0;
    padding: 0;
    margin: auto;

    user-select: text;
    visibility: visible;
    inset-block-start: 0;
    inset-block-end: 0;
}
#favDialog::backdrop{
    display: none;
}
#favDialog::before{
    content: "";
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background: #000000aa;
}

#favDialog,
#favDialog::before{
    animation: fadeout 500ms ease forwards;
}

#favDialog[open],
#favDialog[open]::before{
    animation: fadein 500ms ease forwards;
}

#favDialog form{
    display: block;
    padding: 40px 0 30px 0;
    position: relative;
}
#favDialog .btns{
    text-align: center;
}

#favDialog .btn-close{
    position: absolute;
    top: -35px;
    right: 0;
    width: 30px;
    height: 30px;
    border: none;
    background-color: transparent;
    padding: 0;
}
#favDialog .btn-close:before{
    content: "";
    display: block;
    width: 30px;
    height: 2px;
    background-color: #ffffff;
    transform: rotate(-45deg);
    transform-origin: 50% 50%;
}
#favDialog .btn-close:after{
    content: "";
    display: block;
    width: 30px;
    height: 2px;
    background-color: #ffffff;
    transform: translate(0,-2px) rotate(45deg);
    transform-origin: 50% 50%;
}

#favDialog .content-wrap{
    background-color: #ffffff;
    max-width: 500px;
    width:100%;
    margin: 0 auto;
    padding: 2rem;
    border-radius: 10px;
    border: 1px solid #000000;
    position: relative;
    z-index: 2;
}

@keyframes fadein{
    0%{
        opacity: 0;
    }
    100%{
        opacity: 1;
    }
}
@keyframes fadeout{
    0%{
        opacity: 1;
        display: block;
    }
    99%{
        opacity: 0;
        display: block;
    }
    100%{
        opacity: 0;
        display: none;
    }
}

dialogの挙動が自分が実装したい挙動と違っていたのでCSSで無理やり変更しています。

また、アニメーションがないため、keyframesを設定しています。


JavaScript

(function(){
  window.addEventListener('load',()=>{
    const showButtons = document.querySelectorAll(".showDialog");
    const favDialog = document.getElementById("favDialog");

    // ボタンで <dialog> をモーダルに開く
    showButtons.forEach((item)=>{
      item.addEventListener("click", (e) => {
        let id = e.target.getAttribute('data-id');
        const content = document.querySelector(`#${id}`).content;
        const clone = document.importNode(content, true);
        let $wrap = document.querySelector('#favDialog .content-main');
        for (const child of $wrap.children) {
          $wrap.removeChild(child);
        }
        $wrap.appendChild(clone);

        favDialog.showModal();
      });
    });

    document.querySelector('#favDialog').addEventListener('click',(e)=>{
      if(e.target === e.currentTarget || e.target.tagName.toLowerCase() === 'form'){
        favDialog.close();
      }
    },false);

  },false);

})();

let id = e.target.getAttribute('data-id');
const content = document.querySelector(`#${id}`).content;
const clone = document.importNode(content, true);

クリックしたボタンのdata-idを取得して、template要素を取得して要素をコピーしています。


let $wrap = document.querySelector('#favDialog .content-main');
for (const child of $wrap.children) {
   $wrap.removeChild(child);
}

dialog要素に挿入する前にdialog内の要素を削除しておきます。


$wrap.appendChild(clone);

クローンした要素を挿入


favDialog.showModal();

モーダルを表示


document.querySelector('#favDialog').addEventListener('click',(e)=>{
  if(e.target === e.currentTarget || e.target.tagName.toLowerCase() === 'form'){
     favDialog.close();
  }
},false);

モーダル背景をクリックで閉じるようにしています。


Github

https://github.com/hiron712/dialog_template


ブラウザ対応

IEがほぼなくなった今、一部関数が使えない場合があるのでそこを気をつければ、使用しても良いのではないでしょうか?

dialog

template


まとめ

dialog要素の挙動は決まっているので、自分自身が実装したい挙動と違う場合は難しいかもしれませんが、ブラウザがモーダルウィンドを制御してくれているのでその分のJavaScriptを書かなくて済む、モーダルにフォームが表示できて値を渡すことができる、ESCキーでモーダルを閉じることができるなど、メリットもあるので使用しても良いと思います、

コメントを投稿する

CAPTCHA


関連記事

人気の投稿

最新の投稿

タグ

月別アーカイブ

Contact

WEB制作の依頼など気軽にお問い合わせください。

お問い合わせ