W3docs

HTML-тег <dialog>

HTML-тег <dialog>: show() и showModal(), шаблон form method="dialog", события close и cancel, доступность.

Тег <dialog> — один из элементов HTML5. Он создаёт нативное диалоговое окно — всплывающую панель, такую как сообщение подтверждения, оповещение или форма, — с которой пользователь взаимодействует перед продолжением работы. По умолчанию диалог скрыт; показывать и скрывать его позволяет небольшой JavaScript API.

На этой странице рассмотрены два способа открыть диалог (show() и showModal()), способы закрыть его и получить результат, шаблон <form method="dialog">, события close и cancel, доступность и стилизация подложки.

Зачем использовать нативный <dialog> вместо <div> в роли модального окна?

До появления <dialog> разработчики вручную строили модальные окна из <div> с набором CSS и JavaScript. Нативный элемент делает эту работу за вас и делает это надёжнее:

  • Встроенное удержание фокуса. При открытии через showModal() клавиатурный фокус (Tab / Shift+Tab) удерживается внутри диалога. В <div>-модале удержание фокуса приходится реализовывать вручную, и ошибки здесь — распространённая проблема доступности.
  • Верхний слой отрисовки. Модальный диалог отображается в верхнем слое браузера, поэтому он всегда рисуется поверх остальной страницы независимо от z-index. Никаких войн с z-index.
  • Автоматическая подложка. showModal() рисует псевдоэлемент ::backdrop за диалогом, блокируя клики по странице позади — дополнительный элемент-оверлей не нужен.
  • Закрытие по Escape. Нажатие Esc закрывает модальный диалог автоматически (генерируя событие cancel, на которое можно реагировать).
  • Правильная семантика. Элемент несёт неявную роль role="dialog", поэтому вспомогательные технологии правильно объявляют его без дополнительного ARIA.

Синтаксис

Тег <dialog> используется парой. Поместите содержимое диалога между открывающим (<dialog>) и закрывающим (</dialog>) тегами. Открывать диалог из скрипта можно одним из двух методов DOM-объекта элемента:

  • dialog.show() — открывает немодальный диалог.
  • dialog.showModal() — открывает модальный диалог.
  • dialog.close([returnValue]) — закрывает диалог и при необходимости записывает возвращаемое значение.

Boolean-атрибут open отражает, показан ли диалог в данный момент. Как правило, его не устанавливают вручную — управление берут на себя описанные выше методы.

Немодальные диалоги: show()

show() открывает диалог на месте, не блокируя страницу. Остальная часть документа остаётся интерактивной, ::backdrop отсутствует, фокус не удерживается, и Esc его не закрывает. Это правильный выбор для некритичных, закрываемых панелей — небольшой панели инструментов, заметки «что нового» или встроенного средства выбора.

<!DOCTYPE html>
<html>
  <head>
    <title>Non-modal dialog with show()</title>
  </head>
  <body>
    <button id="open">Open non-modal dialog</button>

    <dialog id="info">
      <p>You can still click and scroll the page behind me.</p>
      <button id="close">Close</button>
    </dialog>

    <script>
      const dialog = document.getElementById("info");

      document.getElementById("open").addEventListener("click", () => {
        dialog.show();
      });

      document.getElementById("close").addEventListener("click", () => {
        dialog.close();
      });
    </script>
  </body>
</html>

Модальные диалоги: showModal()

showModal() открывает диалог как модальный. Это меняет поведение четырьмя важными способами:

  1. Взаимодействие блокируется. Всё вне диалога становится неактивным — клики и ввод с клавиатуры не достигают страницы позади.
  2. Появляется подложка. Браузер отображает псевдоэлемент ::backdrop за диалогом, который можно стилизовать.
  3. Фокус удерживается. Нажатие Tab циклически переходит только между фокусируемыми элементами внутри диалога.
  4. Он помещается в верхний слой. Диалог отрисовывается поверх всего остального содержимого, игнорируя z-index. Нажатие Esc закрывает его.
<!DOCTYPE html>
<html>
  <head>
    <title>Modal dialog with showModal()</title>
    <style>
      dialog {
        width: 40%;
        border: 1px solid #ccc;
        border-radius: 0.5em;
        padding: 1em;
      }
      dialog::backdrop {
        background-color: rgba(0, 0, 0, 0.5);
      }
    </style>
  </head>
  <body>
    <button id="open">Open modal dialog</button>

    <dialog id="confirm">
      <p>The page behind is blocked. Press Esc or a button to close.</p>
      <button id="close">Close dialog</button>
    </dialog>

    <script>
      const dialog = document.getElementById("confirm");

      document.getElementById("open").addEventListener("click", () => {
        dialog.showModal();
      });

      document.getElementById("close").addEventListener("click", () => {
        dialog.close();
      });
    </script>
  </body>
</html>
Result

Шаблон <form method="dialog">

Элемент <form> внутри <dialog> может использовать method="dialog". Отправка такой формы закрывает диалог без отправки сетевого запроса, а значение нажатой кнопки <button> сохраняется в DOM-свойстве returnValue диалога. Это удобный способ определить, какую кнопку выбрал пользователь.

<!DOCTYPE html>
<html>
  <head>
    <title>Dialog with a form</title>
  </head>
  <body>
    <button id="open">Delete file</button>
    <p id="result"></p>

    <dialog id="confirm">
      <form method="dialog">
        <p>Are you sure you want to delete this file?</p>
        <button value="cancel">Cancel</button>
        <button value="delete">Delete</button>
      </form>
    </dialog>

    <script>
      const dialog = document.getElementById("confirm");
      const result = document.getElementById("result");

      document.getElementById("open").addEventListener("click", () => {
        dialog.showModal();
      });

      dialog.addEventListener("close", () => {
        // returnValue is the value of the button that submitted the form
        result.textContent = "You chose: " + dialog.returnValue;
      });
    </script>
  </body>
</html>

returnValue — это свойство DOM-элемента, а не HTML-атрибут — его читают и устанавливают из JavaScript. Его также можно задать напрямую при закрытии из кода: dialog.close("delete").

События close и cancel

Элемент <dialog> генерирует два события, которые можно прослушивать:

СобытиеКогда срабатывает
closeВсякий раз при закрытии диалога — через close(), при отправке формы с method="dialog" или по нажатию Esc. Здесь читают returnValue.
cancelКогда пользователь закрывает модальный диалог клавишей Esc. Срабатывает до close. Вызовите event.preventDefault(), чтобы оставить диалог открытым.
<dialog id="editor">
  <p>Unsaved changes — Esc would normally close me.</p>
  <button onclick="this.closest('dialog').close()">Done</button>
</dialog>

<script>
  const dialog = document.getElementById("editor");

  dialog.addEventListener("cancel", (event) => {
    // Prevent Esc from discarding unsaved work
    event.preventDefault();
  });

  dialog.addEventListener("close", () => {
    console.log("Dialog closed");
  });
</script>

Подробнее о подключении обработчиков событий см. в разделах События JavaScript и JavaScript HTML DOM.

Доступность

Элемент <dialog> имеет неявную роль role="dialog", но ему всё равно необходимо задать доступное имя и управлять фокусом:

  • Именуйте диалог. Укажите в атрибуте aria-labelledby id заголовка диалога, чтобы программы чтения с экрана объявляли его название. Используйте aria-describedby для более подробного описания.
  • Фокус при открытии. showModal() автоматически перемещает фокус внутрь диалога — на первый фокусируемый элемент или элемент, помеченный атрибутом autofocus. Предпочтительно размещать autofocus на безопасном элементе управления (например, Отмена), а не на деструктивном.
  • Возврат фокуса при закрытии. При закрытии диалога верните фокус на элемент управления, который его открыл, чтобы пользователи клавиатуры не оказались в начале страницы. Нативный <dialog> делает это самостоятельно; для максимальной надёжности сохраняйте и восстанавливайте триггер вручную.
<button id="open">Edit profile</button>

<dialog id="profile" aria-labelledby="profile-title" aria-describedby="profile-desc">
  <h2 id="profile-title">Edit profile</h2>
  <p id="profile-desc">Update your display name, then save.</p>
  <form method="dialog">
    <input type="text" aria-label="Display name" autofocus>
    <button value="save">Save</button>
  </form>
</dialog>

<script>
  const openButton = document.getElementById("open");
  const dialog = document.getElementById("profile");

  openButton.addEventListener("click", () => dialog.showModal());

  // Explicitly return focus to the trigger when the dialog closes
  dialog.addEventListener("close", () => openButton.focus());
</script>

Подробнее о создании доступных интерактивных виджетов см. в разделе Доступность DOM.

Стилизация диалога и его подложки

Вы можете стилизовать само диалоговое окно, а для модальных диалогов — область позади него с помощью псевдоэлемента ::backdrop.

dialog {
  border: 1px solid #ccc;
  border-radius: 0.5em;
  padding: 1em;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}

/* Only rendered for dialogs opened with showModal() */
dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.5);
}

Атрибуты

АтрибутЗначениеОписание
openopenBoolean-атрибут, указывающий, что диалог в данный момент показан. Обычно устанавливается автоматически методами show() / showModal().

Тег <dialog> также поддерживает глобальные атрибуты и атрибуты событий.

Практика

Практика
Какие утверждения об HTML-элементе <dialog> верны?
Какие утверждения об HTML-элементе <dialog> верны?
Was this page helpful?