Кратко: проблема в том, что <dialog> рендерится в «top layer» браузера — всё обычное содержимое страницы оказывается под ним и никакие z-index/position не помогут. Надо поместить ваш toast в тот же топ‑лейер, что и диалог, или отказаться от нативного <dialog> и сделать модалку «своими руками».
Ниже — практичные варианты с плюсами/минусами и примерами.
1) Самый простой (если toast нужен только пока открыт диалог) — временно перемещать toast внутрь открытого dialog
- + простая реализация
- − если у вас несколько диалогов/глобальных тостов, может быть неудобно; нужно следить за доступностью
Пример:
```js
const dialog = document.querySelector('dialog');
const toast = document.getElementById('toast');
function openDialog() {
dialog.showModal();
dialog.appendChild(toast); // теперь toast в top-layer вместе с диалогом
toast.style.position = 'fixed'; // фиксируем по окну
toast.style.bottom = '10px';
}
dialog.addEventListener('close', () => {
document.body.appendChild(toast); // возвращаем на место при закрытии
});
```
Не забудьте aria-live/role для озвучивания уведомлений и сделать toast некликабельным (pointer-events: none), если нужно.
2) Сделать отдельный global‑toast в том же топ‑лейере — создать второй <dialog> именно для тостов
- + toast глобальный, не зависит от конкретного диалога; простое управление
- + сохраняется поведение top-layer (всегда над модалями)
- − немного «хак», но работает везде, где поддержан dialog
Пример:
```js
// создаём один раз (при инициализации приложения)
const toastDialog = document.createElement('dialog');
toastDialog.className = 'toast-dialog';
Object.assign(toastDialog.style, {
border: 'none',
background: 'rgba(0,0,0,0.8)',
color: '#fff',
height: '20px',
margin: '0',
padding: '4px 8px',
position: 'fixed',
left: '50%',
transform: 'translateX(-50%)',
bottom: '10px',
pointerEvents: 'none', // не мешаем кликам
});
document.body.appendChild(toastDialog);
toastDialog.show(); // non-modal, но в top-layer
function showToast(text, ms = 3000) {
toastDialog.textContent = text;
setTimeout(() => toastDialog.close(), ms);
// при необходимости снова show() — некоторые браузеры закрывают dialog при close()
if (!toastDialog.open) toastDialog.show();
}
```
3) Отказаться от нативного <dialog> и сделать «свою» модалку (overlay + fixed контейнеры)
- + полный контроль над стэком (z-index), проще показывать toast поверх
- + и часто проще с кросс‑браузерностью и кастомизацией
- − придётся самим реализовать/поддерживать фокус‑менеджмент, backdrop, accessibility (inert, aria атрибуты), что нативный dialog делает за вас
Если выбираете этот путь, делайте модалку с high z-index (например 1000) и toast с ещё большим (1001). Не забывайте про inert/aria-hidden на фоне и управление фокусом.
Дополнительно
- Popover API действительно ещё не везде для 2022‑порага, так что не подходит, если нужна широкая совместимость.
- CSS z-index/position не позволит вывести элемент поверх диалога — dialog топ‑слой «переопределяет» обычный порядок рендеринга.
- Для доступности тостов используйте role="status" или aria-live="polite" (и исключите фокус из тоста, если он не интерактивен).
Рекомендация
- Если вы хотите сохранить нативный <dialog> и при этом иметь глобальные уведомления — реализуйте отдельный глобальный <dialog> для тостов (вариант 2). Это даёт простой и надёжный результат.
- Если у вас сложные сценарии модальных окон и уведомлений, и вы готовы управлять доступностью — можно перейти на кастомную реализацию модалок (вариант 3).
Если нужно, могу прислать готовый пример (HTML/CSS/JS) для вашего проекта: показывающий и диалог, и глобальный toast в top‑layer, с aria-live и корректным поведением при открытии/закрытии.