Элемент dialog и атрибут popover. Инструкции к применению
Рома Ахмадуллин, Дром
Элемент dialog и атрибут popover. Инструкции к применению
Рома Ахмадуллин
Дром
Рома Ахмадуллин
фронтенд-разработчик в Дроме
6 лет в разработке
уважаю веб-стандарты и Open Source
живу во Владивостоке
хожу в горы
<div class="overlay">...</div>
<div class="modal">...</div>
<style>
.overlay {
...
}
.modal {
...
}
</style>
ДОБАВИМ ЧУТОЧКУ JS
УПС
Что может пойти не так?
или
Что важно учесть?
Характеристика
Кастомное решение
Привязка к якорю
❌
new IntersectionObserver(([tooltip]) => {
// обновляем местоположение элемента руками
});
// или с помощью либы
import magicAutoPlacement from 'super-puper-awesome-lib';
magicAutoPlacement(tooltip);
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
<div class="overlay"></div>
<style>
.overlay {
...
}
</style>
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
Явное закрытие
❌
// явное закрытие
closeButton.addEventListener('click', () => {
modal.classList.remove('visible');
});
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
Явное закрытие
❌
Неявное закрытие
❌
// неявное закрытие
outsideArea.addEventListener('click', () => {
sidebar.classList.remove('visible');
});
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
Явное закрытие
❌
Неявное закрытие
❌
Закрытие на Escape
❌
// закрываем модалку на Escape
window.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
modal.classList.remove('visible');
}
});
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
Явное закрытие
❌
Неявное закрытие
❌
Закрытие на Escape
❌
Focus trap
❌
// используем либу
import { createFocusTrap } from 'focus-trap';
createFocusTrap(modal);
<!-- расставляем атрибут inert -->
<div class="modal visible">
...
</div>
<div class="everything-else" inert>
...
</div>
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
Явное закрытие
❌
Неявное закрытие
❌
Закрытие на Escape
❌
Focus trap
❌
Вынос на верхний слой
❌
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
Явное закрытие
❌
Неявное закрытие
❌
Закрытие на Escape
❌
Focus trap
❌
Вынос на верхний слой
❌
Семантика / a11y
❌
<div
role="dialog"
aria-labelledby="modal-label"
aria-modal="true"
class="modal visible"
>
<h3 id="modal-label">Укажите контактные данные</h3>
</div>
Характеристика
Кастомное решение
Привязка к якорю
❌
Внешний вид
❌
Оверлей
❌
Явное закрытие
❌
Неявное закрытие
❌
Закрытие на Escape
❌
Focus trap
❌
Вынос на верхний слой
❌
Семантика / a11y
❌
ВОТ БУДУТ У НАС НАТИВНЫЕ МОДАЛКИ
ЗАЖИВЕМ
<dialog>
<!-- содержимое диалога -->
</dialog>
// открывает диалог в немодальном режиме
element.show();
// открывает диалог в модальном режиме
element.showModal();
// закрывает диалог
element.close();
<dialog open>
<!-- содержимое диалога -->
</dialog>
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
Неявное закрытие
Закрытие на Escape
Focus trap
Вынос на верхний слой
Семантика / a11y
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
Закрытие на Escape
Focus trap
Вынос на верхний слой
Семантика / a11y
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
Focus trap
Вынос на верхний слой
Семантика / a11y
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
Вынос на верхний слой
Семантика / a11y
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
❌
✅
Вынос на верхний слой
Семантика / a11y
<div class="yellow"></div>
<div class="green"></div>
<div class="blue"></div>
Может ли быть несколько элементов на top layer
?
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
❌
✅
Вынос на верхний слой
❌
✅
Семантика / a11y
backdrop
Псевдоэлемент, представляющий собой блок размером с вьюпорт, имеющийся у любого элемента, попавшего в top layer.
CSS-спецификация
CSS-спецификация: backdrop
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
Оверлей
❌
✅
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
❌
✅
Вынос на верхний слой
❌
✅
Семантика / a11y
/* стили для диалога */
dialog {
...
}
/* открытого */
dialog[open] {
...
}
/* модального */
dialog:modal {
...
}
/* бэкдропа */
dialog::backdrop {
...
}
dialog {
transition:
opacity .5s ease-in,
scale .5s ease-in,
display .5s ease-in allow-discrete;
}
dialog {
transition :
opacity .5s ease-in,
scale .5s ease-in,
display .5s ease-in allow-discrete;
}
allow-discrete
Значение свойства transition-behavior
, определяющее, будут ли запущены переходы для свойств, поведение анимации которых является дискретным.
CSS-спецификация
CSS-спецификация: allow-discrete
/* открытый диалог */
dialog {
...
}
/* открывающийся диалог */
@starting-style {
dialog {
...
}
}
/* закрывающийся диалог */
dialog:not([open]) {
...
}
/* открытый диалог */
dialog {
opacity: 1;
scale: 1;
}
/* открывающийся диалог */
@starting-style {
dialog {
opacity: 0;
scale: 1.1;
}
}
/* открытый диалог */
dialog {
opacity: 1;
scale: 1;
}
/* открывающийся диалог */
@starting-style {
dialog {
opacity: 0;
scale: 1.1;
}
}
/* закрывающийся диалог */
dialog:not([open]) {
opacity: 0;
scale: .9;
transition-duration: .4s;
transition-timing-function: ease;
}
@media (prefers-reduced-motion: no-preference) {
/* css для анимации */
}
Характеристика
Dialog
show()
showModal()
Привязка к якорю
Внешний вид
❌
❌
Оверлей
❌
✅
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
❌
✅
Вынос на верхний слой
❌
✅
Семантика / a11y
Характеристика
Dialog
show()
showModal()
Привязка к якорю
❌
❌
Внешний вид
❌
❌
Оверлей
❌
✅
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
❌
✅
Вынос на верхний слой
❌
✅
Семантика / a11y
Характеристика
Dialog
show()
showModal()
Привязка к якорю
❌
❌
Внешний вид
❌
❌
Оверлей
❌
✅
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
❌
✅
Вынос на верхний слой
❌
✅
Семантика / a11y
✅
✅
Характеристика
Dialog
show()
showModal()
Привязка к якорю
❌
❌
Внешний вид
❌
❌
Оверлей
❌
✅
Явное закрытие
✅
✅
Неявное закрытие
❌
❌
Закрытие на Escape
❌
✅
Focus trap
❌
✅
Вынос на верхний слой
❌
✅
Семантика / a11y
✅
✅
<div popover>
<!-- содержимое элемента -->
</div>
<button popovertarget="popover-example">
Показать popover
</button>
<div popover id="popover-example">
Привет! Я поповер!
</div>
<button popovertarget ="popover-example" popovertargetaction ="show" >
Открыть
</button >
<button popovertarget ="popover-example" popovertargetaction ="hide" >
Закрыть
</button >
<button popovertarget ="popover-example" popovertargetaction ="toggle" >
Тоггл
</button >
<div popover id ="popover-example" >
Привет! Я поповер!
</div >
<button popovertarget ="popover-example" popovertargetaction ="show" >
Открыть
</button >
<button popovertarget ="popover-example" popovertargetaction ="hide" >
Закрыть
</button >
<button popovertarget ="popover-example" popovertargetaction ="toggle" >
Тоггл
</button >
<div popover id ="popover-example" >
Привет! Я поповер!
</div >
// показывает поповер
element.showPopover();
// скрывает поповер
element.hidePopover();
// переключает видимость (показывает и скрывает)
element.togglePopover();
<div popover="auto">
...
</div>
<div popover="manual">
...
</div>
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
Неявное закрытие
Закрытие на Escape
Focus trap
Top layer
Семантика / a11y
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
Закрытие на Escape
Focus trap
Top layer
Семантика / a11y
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
Focus trap
Top layer
Семантика / a11y
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
Top layer
Семантика / a11y
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
❌
❌
Top layer
Семантика / a11y
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
Оверлей
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
❌
❌
Top layer
✅
✅
Семантика / a11y
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
Оверлей
✅
✅
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
❌
❌
Top layer
✅
✅
Семантика / a11y
/* стили для поповера */
[popover] {
...
}
/* открытого */
[popover]:popover-open {
...
}
/* бэкдропа */
[popover]::backdrop {
...
}
[popover] {
transition :
opacity .5s ,
scale .5s ,
translate .5s ,
overlay .5s allow-discrete,
display .5s allow-discrete;
}
[popover] {
transition :
opacity .5s ,
scale .5s ,
translate .5s ,
overlay .5s allow-discrete,
display .5s allow-discrete;
}
/* открытый поповер */
[popover]:popover-open {
...
}
/* открывающийся поповер */
@starting-style {
[popover]:popover-open {
...
}
}
/* закрывающийся поповер */
[popover]:not(:popover-open) {
...
}
/* бэкдроп открытого поповера */
[popover]:popover-open::backdrop {
...
}
/* бэкдроп открывающегося поповера */
@starting-style {
[popover]:popover-open::backdrop {
...
}
}
/* бэкдроп закрытого поповера */
[popover]:not(:popover-open)::backdrop {
...
}
@media (prefers-reduced-motion: no-preference) {
/* css для анимации */
}
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
❌
❌
Оверлей
✅
✅
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
❌
❌
Top layer
✅
✅
Семантика / a11y
Popover дает возможность показать контент, семантику добавляем сами.
Характеристика
Popover
auto
manual
Привязка к якорю
Внешний вид
❌
❌
Оверлей
✅
✅
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
❌
❌
Top layer
✅
✅
Семантика / a11y
❌
❌
Позиционирование поповера
<div class="select">
<div class="select-box"></div>
<div class="dropdown"></div>
</div>
<style>
.select {
position: relative;
}
.dropdown {
position: absolute;
top: 40px;
left: 0;
}
</style>
Позиционирование через JavaScript
<button popovertarget="popover-example">
...
</button>
<div popover id="popover-example">
...
</div>
import {
computePosition, offset, autoPlacement, autoUpdate
} from '@floating-ui/dom';
const updatePosition = () => {
computePosition(button, popover, {
middleware: [offset(5), autoPlacement()],
}).then(({x, y}) => {
Object.assign(popover.style, {
left: `${x}px`,
top: `${y}px`,
});
});
};
autoUpdate(button, popover, updatePosition);
[popover] {
/* сбрасываем дефолтные стили */
inset: 0;
margin: 0;
/* выставляем стили необходимые для работы @floating-ui */
width: max-content;
position: absolute;
top: 0;
left: 0;
will-change: transform;
}
Многословно
плюс надо тащить дополнительный JavaScript
<button popovertarget="popover-example">
...
</button>
<div popover id="popover-example">
...
</div>
button [popovertarget="popover-example" ] {
anchor-name : --button-element;
}
[popover] {
inset : unset;
margin : 10px ;
position-anchor : --button-element;
bottom : anchor (top);
justify-self : anchor-center;
}
button [popovertarget="popover-example" ] {
anchor-name : --button-element;
}
[popover] {
inset : unset;
margin : 10px ;
position-anchor : --button-element;
bottom : anchor (top);
justify-self : anchor-center;
}
button [popovertarget="popover-example" ] {
anchor-name : --button-element;
}
[popover] {
inset : unset;
margin : 10px ;
position-anchor : --button-element;
bottom : anchor (top);
justify-self : anchor-center;
}
button [popovertarget="popover-example" ] {
anchor-name : --button-element;
}
[popover] {
inset : unset;
margin : 10px ;
position-anchor : --button-element;
bottom : anchor (top);
justify-self : anchor-center;
}
button [popovertarget="popover-example" ] {
anchor-name : --button-element;
}
[popover] {
inset : unset;
margin : 10px ;
position-anchor : --button-element;
bottom : anchor (top);
justify-self : anchor-center;
}
[popover] {
bottom : anchor (top);
justify-self : anchor-center;
}
[popover] {
bottom : anchor (top);
justify-self : anchor-center;
position-area : top;
position-area : block-start;
}
[popover] {
position-area : top;
position-try-fallbacks : --bottom;
}
@position-try --bottom {
position-area : bottom;
}
[popover] {
position-area : top;
position-try-fallbacks : --bottom;
}
@position-try --bottom {
position-area : bottom;
}
[popover] {
position-area : top;
position-try-fallbacks : --bottom;
}
@position-try --bottom {
position-area : bottom;
}
[popover] {
position-area : top;
position-try-fallbacks : --bottom;
}
@position-try --bottom {
position-area : bottom;
}
/* добавляем стиля поповеру */
[popover] {
background: hsl(0, 0%, 0%);
color: hsl(0, 0%, 100%);
overflow: visible;
}
/* добавляем хвостик тултипа */
[popover]::after {
content: '';
position: absolute;
bottom: -5px;
left: 50%;
transform: translate(-50%, 0px);
transform-origin: center top;
border-style: solid;
border-width: 5px 5px 0px;
border-color: hsl(0, 0%, 0%) transparent transparent;
}
[popover] {
position-anchor : --button-element;
anchor-name : --popover-element;
}
[popover] ::before , [popover] ::after {
position-anchor : --button-element;
content : '' ;
position : fixed;
background : inherit;
margin : auto;
}
[popover] {
position-anchor : --button-element;
anchor-name : --popover-element;
}
[popover] ::before , [popover] ::after {
position-anchor : --button-element;
content : '' ;
position : fixed;
background : inherit;
margin : auto;
}
[popover] {
position-anchor : --button-element;
anchor-name : --popover-element;
}
[popover] ::before , [popover] ::after {
position-anchor : --button-element;
content : '' ;
position : fixed;
background : inherit;
margin : auto;
}
[popover] {
position-anchor : --button-element;
anchor-name : --popover-element;
}
[popover] ::before , [popover] ::after {
position-anchor : --button-element;
content : '' ;
position : fixed;
background : inherit;
margin : auto;
}
[popover] {
position-anchor : --button-element;
anchor-name : --popover-element;
}
[popover] ::before , [popover] ::after {
position-anchor : --button-element;
content : '' ;
position : fixed;
background : inherit;
margin : auto;
}
/* задаем размеры хвостиков */
[popover]::before,
[popover]::after {
left: anchor(--button-element start);
right: anchor(--button-element end);
width: 10px;
max-height: 10px;
}
[popover] ::before {
top : anchor (--button-element end);
bottom : anchor (--popover-element start);
transform : translateY (7px ) rotate (45deg );
}
[popover] ::after {
top : anchor (--popover-element end);
bottom : anchor (--button-element start);
transform : translateY (-7px ) rotate (45deg );
}
[popover] ::before {
top : anchor (--button-element end);
bottom : anchor (--popover-element start);
transform : translateY (7px ) rotate (45deg );
}
[popover] ::after {
top : anchor (--popover-element end);
bottom : anchor (--button-element start);
transform : translateY (-7px ) rotate (45deg );
}
[popover] ::before {
top : anchor (--button-element end);
bottom : anchor (--popover-element start);
transform : translateY (7px ) rotate (45deg );
}
[popover] ::after {
top : anchor (--popover-element end);
bottom : anchor (--button-element start);
transform : translateY (-7px ) rotate (45deg );
}
Без единой строчки JavaScript'a😍
Характеристика
Popover
auto
manual
Привязка к якорю
❌
❌
Внешний вид
❌
❌
Оверлей
✅
✅
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
❌
❌
Top layer
✅
✅
Семантика / a11y
❌
❌
Характеристика
Popover
auto
manual
Привязка к якорю
❌
❌
Внешний вид
❌
❌
Оверлей
✅
✅
Явное закрытие
✅
✅
Неявное закрытие
✅
❌
Закрытие на Escape
✅
❌
Focus trap
❌
❌
Top layer
✅
✅
Семантика / a11y
❌
❌
Какие UI-паттерны закрывают dialog и popover?
<dialog>
диалоговые окна
модальные окна
popover
тултипы
всплывающие нотификации
поля ввода с дропдауном
меню
сайдбары
Как на практике использовать dialog и popover?
<!-- Пример возможного синтаксиса -->
<button
command="show-modal"
commandfor="my-dialog"
>
Открыть диалог
</button>
<dialog id="my-dialog">
...
</dialog>
Эксплейнер для Invoker Commands
⚠️ Proposal
<!-- Пример возможного синтаксиса -->
<button interesttarget="my-popover">
Показать поповер
</button>
<div id="my-popover" popover>
Контент поповера
</div>
Эксплейнер для Interest Invokers
⚠️ Proposal
<!-- Пример возможного синтаксиса -->
<button interesttarget="my-custom" interestaction="custom-action">
Покажу скрытый текст, если проявишь интерес
</button>
<div id="my-custom">Скрытый текст</div>
<script>
const custom = document.getElementById("my-custom");
custom.addEventListener("interest", (e) => {
if (e.action !== "custom-action") return;
custom.classList.add('active')
});
custom.addEventListener("loseinterest", (e) => {
if (e.action !== "custom-action") return;
custom.classList.remove('active')
});
</script>
Эксплейнер для Interest Invokers
⚠️ Proposal
Что разные подходы умеют по дефолту?
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Характеристика
Кастом
Dialog
Popover
show()
showModal()
auto
manual
Привязка к якорю
❌
❌
❌
❌
❌
Внешний вид
❌
❌
❌
❌
❌
Оверлей
❌
❌
✅
✅
✅
Явное закрытие
❌
✅
✅
✅
✅
Неявное закрытие
❌
❌
❌
✅
❌
Закрытие на Escape
❌
❌
✅
✅
❌
Focus trap
❌
❌
✅
❌
❌
Top layer
❌
❌
✅
✅
✅
Семантика / a11y
❌
✅
✅
❌
❌
Нужна поддержка старых браузеров?
Для всего остального есть...
Открыт к диалогу!
Рома Ахмадуллин
Дром