HTML <dialog>: как использовать встроенный элемент для модальных окон
TL;DR
Элемент HTML
Краткое содержание
- Что такое
- Поддержка браузеров и полифиллы
- Пошаговый пример: подтверждение удаления (HTML, CSS, JS)
- Доступность, ограничения и лучшие практики
- Альтернативы, чек-листы и критерии приёмки
- Тесты, сценарии и сниппеты для продакшена
Что такое элемент dialog?
Элемент dialog — это встроенный HTML-тег, похожий на div или span. Он предназначен для создания кастомных диалогов и модальных окон. По сути, это семантический контейнер с API для открытия/закрытия и встроенной поддержкой фоновой подложки (backdrop).
Определение в одну строку: dialog — HTML-контейнер для диалоговых интерфейсов с методами show(), showModal() и close().
Почему стоит использовать dialog?
- Простота: нужен только тег и несколько строк JavaScript.
- Семантика: браузер понимает, что это окно диалога.
- Визуальные удобства: есть стандартная центровка, рамка и отступы.
- Управление: showModal() блокирует фон, show() отображает как встроенный элемент.
Важно: встроенный элемент упрощает работу, но не освобождает от задач по доступности (фокус, aria-атрибуты) и тестированию в разных браузерах.
Поддержка браузеров и полифилл
Поддержка улучшилась, но есть нюансы:
- Современные версии Chrome, Edge и Opera поддерживают dialog нативно.
- Firefox: версии старее Firefox 98 требуют ручного включения или полифилла.
- Safari: версии старее 15.4 не поддерживают dialog.
Если вам нужна корректная работа в старых браузерах, используйте полифилл. Команда Chrome поддерживает полифилл на GitHub, который эмулирует поведение dialog в неподдерживаемых браузерах.
Важно: нативный элемент и полифилл могут вести себя немного иначе. Тестируйте оба варианта.
Пример: подтверждение удаления (шаг за шагом)
В этом примере мы создаём простое модальное подтверждение для кнопки удаления. Всё, что нужно — один HTML-файл.
1. Настройка HTML-файла
Создайте файл index.html и вставьте базовую структуру страницы:
Dialog demo
Это минимальная заготовка для примера.
2. Разметка диалога и кнопки
Добавьте кнопку удаления и сам элемент диалога в body:
Этот HTML создаёт:
- кнопку удаления;
- сам dialog;
- две кнопки внутри диалога для подтверждения/отмены.
Если открыть index.html в браузере, будет видна только кнопка Delete item. Диалог по умолчанию скрыт до вызова метода show() или showModal().
3. JavaScript для открытия и закрытия
Добавим код, который откроет диалог при клике по кнопке и закроет по нажатию кнопок внутри:
const modal = document.querySelector("dialog")
document.querySelector(".button-container button").addEventListener("click", () => {
modal.showModal();
});
const closeBtns = document.getElementsByClassName("close");
for (btn of closeBtns) {
btn.addEventListener("click", () => {
modal.close();
})
}Пояснения:
- showModal() открывает диалог как модальное окно и блокирует взаимодействие с фоном.
- show() откроет диалог в потоке документа (inline).
- close() скрывает диалог. Если необходимо, можно передать значение — modal.close(“yes”); — которое доступно через modal.returnValue.
Даже без JavaScript пользователь может закрыть модальное окно клавишей Esc (если это поддерживается в браузере).
Открытый диалог выглядит так:
4. Стилизация
Ниже пример CSS, который добавляет затемнение подложки и стили для кнопок:
dialog::backdrop {
background: black;
opacity: 0.5;
}
button {
border-radius: 2px;
background-color: white;
border: 1px solid black;
margin: 5px;
box-shadow: 1px 1px 2px grey;
}
dialog {
max-width: 90vw;
border: 1px solid black;
}
После применения CSS диалог будет затемнять фон и иметь более аккуратный вид:
Если вместо showModal() вызвать show(), диалог отображается встроенно:
document.querySelector(".button-container button").addEventListener("click", () => { modal.show(); });Пример встроенного диалога:
Доступность (a11y) и лучшие практики
Элемент dialog полезен, но требует дополнительных усилий для доступности:
- Управление фокусом: при открытии диалога переводите фокус на первый интерактивный элемент. При закрытии возвращайте фокус к элементу, вызвавшему диалог.
- Трейп фокуса: показывайте только элементы внутри диалога при модальном состоянии. В нативном showModal() браузер частично помогает, но иногда нужен кастомный трэп.
- ARIA: используйте aria-labelledby и aria-describedby, если контент требует. Часто достаточно семантики
- Обработка Esc и backdrop: слушайте событие cancel (в некоторых реализациях) и событие close.
Пример управления фокусом:
const trigger = document.querySelector('.button-container button');
const dialog = document.querySelector('dialog');
trigger.addEventListener('click', () => {
dialog.showModal();
const first = dialog.querySelector('button');
if (first) first.focus();
});
dialog.addEventListener('close', () => {
trigger.focus();
});Пример трепа фокуса (упрощённый):
dialog.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
// очень простой треп: блокировать переход за пределы диалога
// для продакшена используйте готовые библиотеки или тщательно протестируйте
e.preventDefault();
}
});Важно: корректная реализация трепа фокуса требует обработки Shift+Tab, циклического перехода и проверки видимых элементов. Для серьёзных проектов рассмотрите проверенные библиотеки для трепа фокуса.
Когда dialog не подходит (контрпримеры)
- Если вам нужна сложная логика управления фокусом и подсветкой клавиш, и вы не готовы её тестировать — лучше взять готовый компонент с доказанной доступностью.
- Если проект должен поддерживать сильно устаревшие браузеры без возможности использовать полифилл.
- Когда требуются специфические анимации или поведение backdrop, которое нативный диалог эмулирует недостаточно удобно.
В таких случаях альтернативы: собственный компонент на базе div + aria, библиотека с a11y-проверками (например, a11y-dialog или компоненты из UI-библиотек).
Альтернативный подход: форма внутри dialog
Тег dialog хорошо работает с формами. Если кнопка внутри должна отправлять данные, удобно использовать формуляр с атрибутом method=”dialog”.
Пример:
// В JS можно получить результат
const dlg = document.getElementById('confirm');
dlg.showModal();
dlg.addEventListener('close', () => {
console.log('returnValue:', dlg.returnValue);
});Это удобный способ передать результат диалога обратно в логику страницы.
Чек-листы по ролям
Разработчик
- Тестировать show() и showModal() в целевых браузерах.
- Обработать close и cancel события.
- Управлять фокусом при открытии и закрытии.
- Вернуть focus к триггеру.
Дизайнер
- Убедиться, что backdrop и контраст текста соответствуют требованиям доступности.
- Определить поведение при маленьких экранах (адаптивность диалога).
QA
- Проверить клавиатурную навигацию (Tab, Shift+Tab, Esc).
- Тестировать в режиме без JavaScript (план деградации).
- Проверить поведение с полифиллом и без него.
Продукт
- Уточнить, какие данные допустимо запрашивать в модальных окнах (безопасность, персональные данные).
- Решить политику на случай несовместимости браузеров.
Критерии приёмки
- Диалог открывается по кнопке и блокирует фон при showModal().
- Фокус переводится в диалог; после закрытия возвращается к триггеру.
- Кнопка Esc закрывает модальное окно.
- При закрытии доступны значения через dialog.returnValue или form method=”dialog”.
- Визуально соответствует дизайн-гайду: контраст, отступы, размеры.
- Поведение протестировано с полифиллом и без него.
Тесты и сценарии приёмки
- Открытие диалога кликом мыши.
- Открытие и закрытие через клавиатуру (Enter/Space/Tab/Esc).
- Возврат фокуса на триггер.
- Закрытие при клике по кнопке “Yes” и возврат ожидаемого returnValue.
- Поведение на мобильных устройствах (адаптивность и скролл).
Безопасность и приватность
- Не храните в диалогах чувствительную информацию без шифрования/аутентификации.
- Не передавайте персональные данные третьим сторонам через модальные формы.
Советы по переходу в продакшен
- Подключите полифилл для старых браузеров, если нужны широкая поддержка и единообразие поведения.
- Автоматизируйте тесты на доступность (axe-core, Pa11y).
- Добавьте unit- и e2e-тесты на открытие/закрытие и поведение фокуса.
Быстрые сниппеты и подсказки (cheat sheet)
- Открыть модальное: modal.showModal();
- Открыть встроенно: modal.show();
- Закрыть: modal.close();
- Получить результат (при использовании form method=”dialog” или modal.close(value)): modal.returnValue
- Стили для фона: dialog::backdrop { background: rgba(0,0,0,0.5); }
Решение: когда выбрать dialog или библиотеку?
- Небольшие проекты и панели подтверждения: dialog нативный — выбирайте его.
- Критичные по доступности продукты с сложной логикой и поддержкой старых браузеров: берите проверенную библиотеку и интегрируйте только после обзора её тестов по a11y.
Итог
HTML-элемент dialog — удобный и семантичный инструмент для создания модальных окон и встроенных диалогов. Он экономит время и упрощает базовую реализацию. При этом нужно учесть доступность, управление фокусом и совместимость с браузерами. Для простых модальных окон dialog — отличное решение; для сложных сценариев может понадобиться полифилл или проверенная сторонняя библиотека.
Краткое резюме:
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone