← 動的パーツギャラリーへ戻る

パーツ番号 08-10-06 ・ JavaScript使用

Escで閉じるフォーカストラップモーダル

開くとモーダル内にフォーカスが移動して閉じ込められ、Escキーまたはボタンで閉じると呼び出し元へフォーカスが戻ります。WordPressの確認ダイアログに最適です。

jsoverlay

プレビュー

ソースコード

HTML

<div class="d08-10-06-demo">
          <button class="d08-10-06-open" type="button">モーダルを開く</button>
          <div class="d08-10-06-overlay" hidden>
            <div class="d08-10-06-modal" role="dialog" aria-modal="true" aria-labelledby="d08-10-06-title">
              <h4 id="d08-10-06-title" class="d08-10-06-title">確認</h4>
              <p class="d08-10-06-text">Escキーまたは下のボタンで閉じます。フォーカスはモーダル内に留まります。</p>
              <div class="d08-10-06-actions">
                <button class="d08-10-06-cancel" type="button">キャンセル</button>
                <button class="d08-10-06-ok" type="button">OK</button>
              </div>
            </div>
          </div>
        </div>

CSS

.d08-10-06-demo{position:relative;width:100%;display:flex;justify-content:center}
        .d08-10-06-open{background:#2a2d3a;color:#fff;border:none;border-radius:10px;padding:11px 20px;font-size:13px;font-weight:600;cursor:pointer}
        .d08-10-06-overlay{position:absolute;inset:0;background:rgba(20,20,30,.5);display:flex;align-items:center;justify-content:center;border-radius:12px;animation:d08-10-06-fade .18s ease}
        @keyframes d08-10-06-fade{from{opacity:0}to{opacity:1}}
        .d08-10-06-modal{background:#fff;border-radius:14px;padding:20px;width:88%;max-width:260px;box-shadow:0 20px 40px rgba(0,0,0,.25);animation:d08-10-06-pop .22s cubic-bezier(.3,1,.4,1)}
        @keyframes d08-10-06-pop{from{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}
        .d08-10-06-title{margin:0 0 8px;font-size:15px;font-weight:700}
        .d08-10-06-text{margin:0 0 16px;font-size:12px;color:#666}
        .d08-10-06-actions{display:flex;gap:8px;justify-content:flex-end}
        .d08-10-06-cancel,.d08-10-06-ok{border:none;border-radius:8px;padding:8px 14px;font-size:12.5px;font-weight:600;cursor:pointer}
        .d08-10-06-cancel{background:#eef0f3;color:#444}
        .d08-10-06-ok{background:#6a5cff;color:#fff}
        .d08-10-06-cancel:focus-visible,.d08-10-06-ok:focus-visible,.d08-10-06-open:focus-visible{outline:2px solid #6a5cff;outline-offset:2px}

JavaScript

(function(){
        var root=document.querySelector('#item-08-10-06 .d08-10-06-demo');if(!root)return;
        var openBtn=root.querySelector('.d08-10-06-open');
        var overlay=root.querySelector('.d08-10-06-overlay');
        var modal=root.querySelector('.d08-10-06-modal');
        var cancelBtn=root.querySelector('.d08-10-06-cancel');
        var okBtn=root.querySelector('.d08-10-06-ok');
        var focusables=[cancelBtn,okBtn];
        function openModal(){
          overlay.hidden=false;
          cancelBtn.focus();
          document.addEventListener('keydown',onKeydown,true);
        }
        function closeModal(){
          overlay.hidden=true;
          document.removeEventListener('keydown',onKeydown,true);
          openBtn.focus();
        }
        function onKeydown(e){
          if(e.key==='Escape'){e.preventDefault();closeModal();return;}
          if(e.key==='Tab'){
            var idx=focusables.indexOf(document.activeElement);
            if(e.shiftKey){
              if(idx<=0){e.preventDefault();focusables[focusables.length-1].focus();}
            }else{
              if(idx===focusables.length-1||idx===-1){e.preventDefault();focusables[0].focus();}
            }
          }
        }
        openBtn.addEventListener('click',openModal);
        cancelBtn.addEventListener('click',closeModal);
        okBtn.addEventListener('click',closeModal);
      })();

クラス名 .d08-10-06 は本ライブラリ内での識別用です。複数のパーツを同じページで使う場合は、重複しないよう名前を変更してください。