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() открывает диалог как модальный. Это меняет поведение четырьмя важными способами:
- Взаимодействие блокируется. Всё вне диалога становится неактивным — клики и ввод с клавиатуры не достигают страницы позади.
- Появляется подложка. Браузер отображает псевдоэлемент
::backdropза диалогом, который можно стилизовать. - Фокус удерживается. Нажатие Tab циклически переходит только между фокусируемыми элементами внутри диалога.
- Он помещается в верхний слой. Диалог отрисовывается поверх всего остального содержимого, игнорируя
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>Шаблон <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-labelledbyid заголовка диалога, чтобы программы чтения с экрана объявляли его название. Используйте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);
}Атрибуты
| Атрибут | Значение | Описание |
|---|---|---|
open | open | Boolean-атрибут, указывающий, что диалог в данный момент показан. Обычно устанавливается автоматически методами show() / showModal(). |
Тег <dialog> также поддерживает глобальные атрибуты и атрибуты событий.