Тег dialog

Тег dialog


Кратко

Тег создаёт всплывающее окно или диалог. По умолчанию не показывается на странице.

Может открываться в двух режимах:

  1. всплывающее окно — не блокирует взаимодействие со страницей;
  2. модальное окно — откроется поверх страницы, имеет фоновое затемнение, остальной контент не доступен для взаимодействия.

Пример


<dialog>
  Привет, мир!
</dialog>

Скопировать

Как пишется

Парный тег, внутри которого располагается контент всплывающего окна. На <dialog> не должен использоваться атрибут tabindex.

Как открыть

Как и у элемента <details>, по умолчанию содержание окна скрыто от пользователя, но его можно отобразить через атрибут open.


<dialog open>
  Я виден. Привет! 👋
</dialog>

<dialog>
  Я скрыт от пользователя 🥷
</dialog>

Скопировать

Также окно можно открыть с помощью JavaScript-методов:

  1. show() — добавляет атрибут open.
  2. showModal() — открывает в режиме «модального окна». Появляется подложка в виде псевдоэлемента ::backdrop, который можно стилизовать.

<button type="button" onclick="window.myDialog.show();">Просто открыть</button>
<button type="button" onclick="window.myDialog.showModal();">Открыть как модалку</button>
<dialog id="myDialog">🖖 Живи долго и процветай!</dialog>

Скопировать
Открыть демо в новой вкладке

Как закрыть

Закрыть диалог можно как с помощью метода close() в JavaScript, так и в HTML с помощью формы с method="dialog".


<dialog open="open" id="closeMe">
  <h1>Закрой меня! 🙏</h1>
  <p>Результат этих кнопок одинаковый</p>
  <button type="button" onclick="window.closeMe.close();">
    Закрыть с помощью JS
  </button>
  <form method="dialog">
    <button>Закрыть с помощью формы</button>
  </form>
</dialog>

Скопировать
Открыть демо в новой вкладке

Возвращаемое значение

Если кнопкам в форме задать value, то при закрытии диалога это значение будет присваиваться dialog.returnValue.

Присвоим двум кнопкам разные значения:


<form class="options" method="dialog">
  <button class="button button--dark" value="debug">Дави его!</button>
  <button class="button button--light" value="reproduction">Каждая жизнь священна</button>
</form>

Скопировать

Если всплывающее окно закрыто по кнопке Дави его!, то количество 🐞 уменьшается. А если по кнопке Каждая жизнь священна, то увеличивается:


if (dialog.returnValue === "debug") {
  bugs.innerText = bugs.innerText.substring(0, bugs.innerText.length - 2)
} else {
  bugs.innerText += "🐞"
}

Скопировать
Открыть демо в новой вкладке

Как понять

Долгое время в HTML не существовало тега для создания всплывающих окон. Если такая задача возникала, то использовались либо самописные решения для красивых попапов, либо JavaScript-методы alert()prompt() и confirm(), если красота была не важна.

Тег <dialog> появился как альтернатива. Хорошее диалоговое окно — это не просто логика «Показать» и «Скрыть». В <dialog> реализовано то, о чём часто забывают:

  • Для инструментов доступности <dialog> воспринимается как аналог role="dialog". А если оно открыто в режиме модального окна, то и как аналог aria-modal="true".
  • Модальные диалоги закрываются по нажатию на Esc.
  • У модального диалога при открытии появляется «ловушка фокуса»: для клавиатурной навигации доступны только интерактивные элементы только текущего диалога.
  • Браузер запоминает какой элемент был в фокусе до открытия окна и после закрытия окна снова переводит его в фокус.

Вся это логика реализована в самом браузере «из коробки». А значит мы отправляем пользователю меньше трафика.

Подсказки

💡 Google Chrome при закрытии модального окна по Esc ставит предыдущий элемент не просто :focus, а в :focus-visible. Подразумевая, что пользователь перешёл на клавиатурную навигацию.

💡 По нажатию Esc сначала запускается событие cancel, а затем close. Это может быть полезно, если мы хотим отгородить пользователя от случайного нажатия клавиши, сначала предупредив, что изменённые данные не сохранятся, и только при повторном нажатии закрывать окно.

💡 Контент <dialog> по умолчанию скрыт с помощью display: none. Можно переписать это поведение в стилях и анимировать открытие и закрытие. Намного легче, чем аналогичная задача в <details> например.

💡 Модальные окна «ускользают» от контекста. Даже если вы разметили модальное окно в вёрстке перед <div> с z-index: 99999, модальное окно всё равно откроется поверх него. Или если вы наклонили родителя <dialog> с помощью skew(), то попап всё равно откроется без искажений.



Report Page