Тег dialog

Кратко
Тег создаёт всплывающее окно или диалог. По умолчанию не показывается на странице.
Может открываться в двух режимах:
- всплывающее окно — не блокирует взаимодействие со страницей;
- модальное окно — откроется поверх страницы, имеет фоновое затемнение, остальной контент не доступен для взаимодействия.
Пример
<dialog> Привет, мир! </dialog> Скопировать
Как пишется
Парный тег, внутри которого располагается контент всплывающего окна. На <dialog> не должен использоваться атрибут tabindex.
Как открыть
Как и у элемента <details>, по умолчанию содержание окна скрыто от пользователя, но его можно отобразить через атрибут open.
<dialog open> Я виден. Привет! 👋 </dialog> <dialog> Я скрыт от пользователя 🥷 </dialog> Скопировать
Также окно можно открыть с помощью JavaScript-методов:
show()— добавляет атрибутopen.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(), то попап всё равно откроется без искажений.