dialog

<dialog> -- нативный HTML-элемент для модальных и немодальных диалоговых окон. Автоматически управляет фокусом, backdrop, закрытием по Escape и доступностью.

Зачем нужно

До <dialog> каждый разработчик писал модалки вручную: overlay, z-index, focus trap, закрытие по Escape, блокировка скролла. <dialog> решает всё это нативно. Браузер сам создаёт backdrop, ловит фокус внутри диалога, закрывает по Escape, блокирует взаимодействие с фоном.

Где используется

  • Модальные окна подтверждения (удаление, выход)
  • Формы в диалогах (логин, настройки)
  • Информационные попапы
  • Lightbox для изображений

Предпосылки

Базовый синтаксис

<!-- Dialog по умолчанию скрыт -->
<dialog id="my-dialog">
  <h2>Заголовок диалога</h2>
  <p>Содержимое диалога</p>
  <button id="close-btn">Закрыть</button>
</dialog>

<button id="open-btn">Открыть диалог</button>

<script>
  const dialog = document.getElementById('my-dialog');
  const openBtn = document.getElementById('open-btn');
  const closeBtn = document.getElementById('close-btn');

  openBtn.addEventListener('click', () => {
    dialog.showModal; // Модальный (блокирует фон)
  });

  closeBtn.addEventListener('click', () => {
    dialog.close(); // Закрыть
  });
</script>

showModal vs show

// showModal -- МОДАЛЬНЫЙ диалог
dialog.showModal;
// - Блокирует взаимодействие с фоном
// - Показывает ::backdrop
// - Focus trap (Tab не выходит за диалог)
// - Закрытие по Escape
// - Элемент на top layer (поверх всего)

// show -- НЕМОДАЛЬНЫЙ диалог
dialog.show;
// - Фон остаётся интерактивным
// - Нет ::backdrop
// - Нет focus trap
// - Нет закрытия по Escape
// - Просто видимый элемент

close и returnValue

<dialog id="confirm-dialog">
  <h2>Удалить файл?</h2>
  <p>Это действие необратимо.</p>
  <form method="dialog">
    <!-- method="dialog" закрывает диалог, значение кнопки → returnValue -->
    <button value="cancel">Отмена</button>
    <button value="confirm">Удалить</button>
  </form>
</dialog>

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

  dialog.addEventListener('close', () => {
    console.log(dialog.returnValue); // "cancel" или "confirm"

    if (dialog.returnValue === 'confirm') {
      deleteFile;
    }
  });

  // Программное закрытие с returnValue
  dialog.close('custom-value');
</script>

::backdrop -- стилизация фона

/* ::backdrop -- псевдоэлемент фона за модальным диалогом */
dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
}

/* Анимация backdrop */
dialog::backdrop {
  background: rgba(0, 0, 0, 0);
  transition: background 0.3s ease;
}

dialog[open]::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

Стилизация dialog

dialog {
  border: none;
  border-radius: 12px;
  padding: 24px;
  max-width: 480px;
  width: 90%;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}

/* Анимация появления */
dialog {
  opacity: 0;
  transform: translateY(-20px) scale(0.95);
  transition: opacity 0.3s ease, transform 0.3s ease,
              display 0.3s ease allow-discrete,
              overlay 0.3s ease allow-discrete;
}

dialog[open] {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* Starting style для анимации открытия (Chrome 117+) */
@starting-style {
  dialog[open] {
    opacity: 0;
    transform: translateY(-20px) scale(0.95);
  }
}

Закрытие по клику на backdrop

dialog.addEventListener('click', (e) => {
  // Клик на сам dialog (backdrop) -- закрыть
  // Клик на содержимое -- не закрывать
  if (e.target === dialog) {
    dialog.close();
  }
});

Альтернативный подход с wrapper:

<dialog id="modal">
  <div class="dialog-content">
    <h2>Заголовок</h2>
    <p>Содержимое</p>
  </div>
</dialog>
dialog {
  padding: 0;
  background: transparent;
}

.dialog-content {
  padding: 24px;
  background: white;
  border-radius: 12px;
}

Полный пример: форма в диалоге

<dialog id="login-dialog" aria-labelledby="login-title">
  <form method="dialog" id="login-form">
    <h2 id="login-title">Вход в аккаунт</h2>

    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required autofocus>

    <label for="password">Пароль:</label>
    <input type="password" id="password" name="password" required>

    <div class="dialog-actions">
      <button type="button" id="cancel-login">Отмена</button>
      <button type="submit" value="login">Войти</button>
    </div>
  </form>
</dialog>

<script>
  const loginDialog = document.getElementById('login-dialog');
  const loginForm = document.getElementById('login-form');

  document.getElementById('login-btn').addEventListener('click', () => {
    loginDialog.showModal;
  });

  document.getElementById('cancel-login').addEventListener('click', () => {
    loginDialog.close('cancel');
  });

  loginForm.addEventListener('submit', (e) => {
    // method="dialog" закроет диалог
    const formData = new FormData(loginForm);
    handleLogin(formData);
  });

  loginDialog.addEventListener('close', () => {
    loginForm.reset(); // Очистить форму при закрытии
  });
</script>

Доступность dialog

<!-- aria-labelledby для заголовка -->
<dialog aria-labelledby="dialog-title">
  <h2 id="dialog-title">Подтверждение</h2>
  ...
</dialog>

<!-- aria-describedby для описания -->
<dialog aria-labelledby="title" aria-describedby="desc">
  <h2 id="title">Удаление</h2>
  <p id="desc">Файл будет удалён безвозвратно.</p>
  ...
</dialog>

<dialog> автоматически:

  • Устанавливает role="dialog"
  • Создаёт focus trap при showModal
  • Закрывается по Escape
  • Возвращает фокус на элемент, который открыл диалог

Частые ошибки

Ошибка Проблема Решение
dialog.style.display = 'block' Нет focus trap и backdrop Использовать showModal
Нет aria-labelledby SR не знает заголовок Связать с <h2>
Нет кнопки закрытия Только Escape для закрытия Добавить явную кнопку
autofocus на неправильном элементе Фокус не на первом поле autofocus на первом input
Не очищать форму при закрытии Старые данные при повторном открытии form.reset() в close handler

Практика

  1. Создай модальное окно подтверждения с showModal и returnValue
  2. Стилизуй ::backdrop с blur-эффектом
  3. Реализуй закрытие по клику на backdrop
  4. Создай форму в диалоге с валидацией
  5. Добавь анимацию открытия/закрытия через CSS transitions

Связанные темы

Ресурсы