JavaScript Tips | UI・画面部品:Modalを開く

JavaScript JavaScript
スポンサーリンク
スポンサーリンク
  1. Modalを開くユーティリティは「ユーザーの集中を一時的に一点に集めるための仕組み」です
  2. ステップ1:Modalの基本構造を理解する
    1. 典型的なModalのHTML構造
  3. ステップ2:CSSで「開いている状態」と「閉じている状態」を切り替えられるようにする
    1. 例:CSSの基本
  4. ステップ3:Modalを開く・閉じるための基本ユーティリティ
    1. 基本ユーティリティ
    2. 使用例
  5. ステップ4:ボタンとModalを紐づける(イベントハンドラ)
    1. HTML側の例
    2. JavaScriptでイベントを設定する
  6. ステップ5:業務でよくある「確認Modal」のテンプレート
    1. HTMLテンプレート例
    2. JavaScriptで「OKボタンの動作」を紐づける
  7. ステップ6:アクセシビリティ(キーボード操作・フォーカス制御)への配慮(重要な深掘り)
    1. 押さえておきたいポイント
    2. フォーカス制御の簡易実装例
    3. Escキーで閉じる処理の例
  8. ステップ7:複数Modalを扱うときの設計(シンプルさを保つ)
    1. 方針
    2. 例:複数Modalのセットアップ
  9. ステップ8:絶対に避けるべき危険な・使いづらいパターンを明確にしておく
    1. 1. Modalを「DOMの書き換えだけ」で毎回生成する
    2. 2. Modalを閉じる手段がない
    3. 3. 背景側の操作ができてしまう
  10. ステップ9:チームで共有するための「Modal設計ルール」をコードとドキュメントに刻む
    1. コードコメントで明示する
    2. レビュー時のチェックポイント
  11. まとめ:Modalを開くユーティリティは「ユーザーの集中を一時的に一点に集めるための、実務的で欠かせないUI技術」です

Modalを開くユーティリティは「ユーザーの集中を一時的に一点に集めるための仕組み」です

業務システムやWebアプリケーションでは、Modal(モーダルダイアログ)は非常によく使われます。

  • 確認ダイアログ(削除確認、送信確認など)
  • 詳細情報の表示(レコードの詳細、ヘルプテキストなど)
  • フォーム入力(小さな編集フォーム、設定変更など)

Modalは「画面の上に重ねて表示される小さなウィンドウ」であり、 ユーザーの視線と操作を一時的にそこへ集中させるためのUI部品です。

ここでは、初心者向けに、

  • Modalの基本構造
  • JavaScriptでModalを開く・閉じるユーティリティ
  • 業務で使いやすい設計と注意点

をステップバイステップで解説していきます。

ステップ1:Modalの基本構造を理解する

まず、ModalがどのようなHTML構造でできているかを押さえます。

典型的なModalのHTML構造

<div class="modal-backdrop" id="my-modal" aria-hidden="true">
  <div class="modal">
    <div class="modal-header">
      <h2 class="modal-title">タイトル</h2>
      <button class="modal-close" type="button" aria-label="閉じる">×</button>
    </div>
    <div class="modal-body">
      ここに内容が入ります。
    </div>
    <div class="modal-footer">
      <button type="button" class="modal-cancel">キャンセル</button>
      <button type="button" class="modal-ok">OK</button>
    </div>
  </div>
</div>

ここで重要なのは次の点です。

  • modal-backdrop:画面全体を覆う半透明の背景(クリックを遮る役割もあります)
  • modal:中央に表示されるダイアログ本体
  • ヘッダー・ボディ・フッター:タイトル、内容、ボタンなどを配置する領域

CSS側では、

  • 初期状態では非表示(display: none や opacity: 0)
  • Modalを開くときにクラスを付け替えて表示する

というスタイルにしておくことが多いです。

ステップ2:CSSで「開いている状態」と「閉じている状態」を切り替えられるようにする

JavaScriptでModalを開くためには、 CSS側で「開いている状態」と「閉じている状態」を切り替えられるようにしておく必要があります。

例:CSSの基本

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: none;          /* 初期状態は非表示 */
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal-backdrop.is-open {
  display: flex;          /* 開いているときは中央寄せで表示 */
}

.modal {
  background: #fff;
  border-radius: 4px;
  padding: 16px;
  max-width: 480px;
  width: 100%;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}

ここでは、

  • .modal-backdrop に display: none を設定して非表示にしておき、
  • .modal-backdrop.is-open のときだけ display: flex で表示する

というシンプルな切り替えをしています。

ポイント:JavaScript側では「クラスを付ける/外す」だけで開閉できるようにしておくと、実装がシンプルになります。

ステップ3:Modalを開く・閉じるための基本ユーティリティ

次に、JavaScriptでModalを開く・閉じるためのユーティリティを作ります。

基本ユーティリティ

export const ModalController = {
  open(modalId) {
    const el = document.getElementById(modalId);
    if (!el) return;
    el.classList.add("is-open");
    el.setAttribute("aria-hidden", "false");
  },

  close(modalId) {
    const el = document.getElementById(modalId);
    if (!el) return;
    el.classList.remove("is-open");
    el.setAttribute("aria-hidden", "true");
  },
};
JavaScript

使用例

// Modalを開く
ModalController.open("my-modal");

// Modalを閉じる
ModalController.close("my-modal");
JavaScript

このようにしておけば、

  • HTML側では id="my-modal" を付けておくだけで、
  • JavaScriptから簡単に開閉できるようになります。

ステップ4:ボタンとModalを紐づける(イベントハンドラ)

Modalは「ボタンを押したら開く」「閉じるボタンを押したら閉じる」という動きが基本です。

HTML側の例

<button type="button" data-modal-open="my-modal">
  詳細を見る
</button>

<div class="modal-backdrop" id="my-modal" aria-hidden="true">
  <div class="modal">
    <div class="modal-header">
      <h2 class="modal-title">詳細情報</h2>
      <button class="modal-close" type="button" aria-label="閉じる">×</button>
    </div>
    <div class="modal-body">
      ここに詳細情報が入ります。
    </div>
    <div class="modal-footer">
      <button type="button" class="modal-cancel">キャンセル</button>
      <button type="button" class="modal-ok">OK</button>
    </div>
  </div>
</div>

JavaScriptでイベントを設定する

function setupModalTriggers() {
  // 開くボタン
  document.querySelectorAll("[data-modal-open]").forEach((btn) => {
    const modalId = btn.getAttribute("data-modal-open");
    btn.addEventListener("click", () => {
      ModalController.open(modalId);
    });
  });

  // 閉じるボタン(× や キャンセル)
  document.querySelectorAll(".modal-backdrop").forEach((backdrop) => {
    const modalId = backdrop.id;

    // ×ボタン
    const closeBtn = backdrop.querySelector(".modal-close");
    if (closeBtn) {
      closeBtn.addEventListener("click", () => {
        ModalController.close(modalId);
      });
    }

    // キャンセルボタン
    const cancelBtn = backdrop.querySelector(".modal-cancel");
    if (cancelBtn) {
      cancelBtn.addEventListener("click", () => {
        ModalController.close(modalId);
      });
    }
  });
}

document.addEventListener("DOMContentLoaded", setupModalTriggers);
JavaScript

これにより、

  • data-modal-open="my-modal" を持つボタンをクリックすると my-modal が開く
  • Modal内の × や キャンセル ボタンをクリックすると閉じる

という基本的な動きが実現できます。

ステップ5:業務でよくある「確認Modal」のテンプレート

業務システムでは、「削除してよいですか?」のような確認Modalが頻出します。

HTMLテンプレート例

<button type="button" data-modal-open="delete-confirm-modal">
  削除
</button>

<div class="modal-backdrop" id="delete-confirm-modal" aria-hidden="true">
  <div class="modal">
    <div class="modal-header">
      <h2 class="modal-title">削除確認</h2>
      <button class="modal-close" type="button" aria-label="閉じる">×</button>
    </div>
    <div class="modal-body">
      このレコードを削除します。よろしいですか?
    </div>
    <div class="modal-footer">
      <button type="button" class="modal-cancel">キャンセル</button>
      <button type="button" class="modal-ok">削除する</button>
    </div>
  </div>
</div>

JavaScriptで「OKボタンの動作」を紐づける

function setupDeleteConfirmModal(onConfirm) {
  const backdrop = document.getElementById("delete-confirm-modal");
  if (!backdrop) return;

  const okBtn = backdrop.querySelector(".modal-ok");
  const modalId = backdrop.id;

  if (okBtn) {
    okBtn.addEventListener("click", () => {
      ModalController.close(modalId);
      onConfirm(); // 実際の削除処理を呼び出す
    });
  }
}

// 使用例
document.addEventListener("DOMContentLoaded", () => {
  setupModalTriggers();

  setupDeleteConfirmModal(() => {
    // ここに削除処理を書く
    console.log("削除処理を実行します");
  });
});
JavaScript

ポイント:Modalは「ユーザーに確認させる場」として使うことが多く、 OKボタンの動作を関数として渡せるようにしておくと、再利用性が高まります。

ステップ6:アクセシビリティ(キーボード操作・フォーカス制御)への配慮(重要な深掘り)

Modalは「画面の上に重ねて表示されるUI」なので、 アクセシビリティ(特にキーボード操作)への配慮が重要です。

押さえておきたいポイント

  1. Modalを開いたときに、フォーカスをModal内の要素に移す
    • 例:最初のボタンや閉じるボタンにフォーカスを当てる。
  2. Escキーで閉じられるようにする(必要に応じて)
    • ユーザーがキーボードだけで操作できるようにする。
  3. Modalが開いている間は、背景側の要素にフォーカスが移動しないようにする
    • 本格的な「フォーカストラップ」は少し難しいですが、 少なくとも「Tabキーで背景に飛んでしまう」状態は避けたいです。

フォーカス制御の簡易実装例

export const ModalController = {
  open(modalId) {
    const el = document.getElementById(modalId);
    if (!el) return;
    el.classList.add("is-open");
    el.setAttribute("aria-hidden", "false");

    // 最初のフォーカス対象を決める
    const focusTarget =
      el.querySelector(".modal-ok") ||
      el.querySelector(".modal-close") ||
      el.querySelector("button") ||
      el;
    if (focusTarget && typeof focusTarget.focus === "function") {
      focusTarget.focus();
    }
  },

  close(modalId) {
    const el = document.getElementById(modalId);
    if (!el) return;
    el.classList.remove("is-open");
    el.setAttribute("aria-hidden", "true");
  },
};
JavaScript

Escキーで閉じる処理の例

function setupModalEscClose(modalId) {
  document.addEventListener("keydown", (event) => {
    if (event.key === "Escape") {
      ModalController.close(modalId);
    }
  });
}

// 使用例
document.addEventListener("DOMContentLoaded", () => {
  setupModalEscClose("my-modal");
});
JavaScript

ポイント:Modalは「ユーザーの操作を一時的にそこへ集中させるUI」なので、 キーボード操作でも自然に扱えるようにしておくことが、業務システムでは特に重要です。

ステップ7:複数Modalを扱うときの設計(シンプルさを保つ)

業務システムでは、複数種類のModalを使うことがよくあります。

  • 削除確認Modal
  • 詳細表示Modal
  • 設定変更Modal

このとき、設計が複雑になりすぎないようにするために、 次のような方針を取るとよいです。

方針

  • 「1つのModalに1つの役割」 を持たせる
  • Modalごとに id を付けて、ユーティリティから開閉する
  • 共通部分(開閉・フォーカス制御)は ModalController に集約する
  • イベント固有の処理(削除、保存など)は別関数として切り出す

例:複数Modalのセットアップ

document.addEventListener("DOMContentLoaded", () => {
  setupModalTriggers();

  setupDeleteConfirmModal(() => {
    console.log("削除処理");
  });

  setupSettingsModal(() => {
    console.log("設定保存処理");
  });
});

function setupSettingsModal(onSave) {
  const backdrop = document.getElementById("settings-modal");
  if (!backdrop) return;

  const saveBtn = backdrop.querySelector(".modal-ok");
  const modalId = backdrop.id;

  if (saveBtn) {
    saveBtn.addEventListener("click", () => {
      ModalController.close(modalId);
      onSave();
    });
  }
}
JavaScript

ステップ8:絶対に避けるべき危険な・使いづらいパターンを明確にしておく

1. Modalを「DOMの書き換えだけ」で毎回生成する

// 毎回 innerHTML でModalを生成する例(推奨しません)
document.body.innerHTML += `
  <div class="modal-backdrop">...</div>
`;
JavaScript

これは、

  • 同じModalが何度もDOMに増殖する
  • イベントハンドラが重複して設定される
  • メモリリークや予期しない挙動の原因になる

などの問題があります。

結論:Modalは基本的に「HTMLとしてあらかじめ用意しておき、開閉だけを制御する」方が安全で分かりやすいです。

2. Modalを閉じる手段がない

  • 閉じるボタンがない
  • Escキーでも閉じられない
  • 背景クリックでも閉じられない

これは、ユーザーが「Modalに閉じ込められる」状態になり、 非常に使いづらいUIになります。

3. 背景側の操作ができてしまう

  • Modalが開いているのに、背景のボタンがクリックできる
  • 背景のフォームにフォーカスが移ってしまう

これは、Modalの意味が薄れてしまい、 ユーザーの操作が混乱しやすくなります。

ステップ9:チームで共有するための「Modal設計ルール」をコードとドキュメントに刻む

コードコメントで明示する

// 注意:
// Modalは、画面の上に重ねて表示されるUI部品です。
// ModalController を使って開閉を制御し、
// .modal-backdrop に is-open クラスを付け外しすることで表示状態を切り替えてください。
// Modalには必ず閉じる手段(×ボタン、キャンセルボタン、Escキーなど)を用意し、
// ユーザーが操作に行き詰まらないようにしてください。
JavaScript

レビュー時のチェックポイント

  • ModalのHTML構造が統一されているか(backdrop・header・body・footer)
  • 開閉処理が ModalController に集約されているか
  • 閉じる手段が複数用意されているか(×、キャンセル、Escなど)
  • キーボード操作でModalを扱えるか(フォーカス制御)

こうしたルールをチームで共有することで、 「Modalごとにバラバラな実装」「閉じられないModal」などの問題を防ぎやすくなります。

まとめ:Modalを開くユーティリティは「ユーザーの集中を一時的に一点に集めるための、実務的で欠かせないUI技術」です

Modalを開くためのJavaScriptユーティリティと設計を導入することで、次のような効果があります。

  • どの画面でも同じ方法でModalを開閉できる
  • 確認ダイアログや詳細表示などを簡単に追加できる
  • アクセシビリティや使いやすさを保ったまま、複数Modalを運用できる
  • チーム全体で「Modalの安全で分かりやすい使い方」を共有しやすくなる

業務システムでは、Modalは「ユーザーの重要な判断を支える場」として使われることが多いです。

そのModalを、きちんとしたユーティリティと設計で扱うことは、 ユーザー体験とシステムの信頼性を高めるうえで、とても実務的で重要な技術だと言えます。

タイトルとURLをコピーしました