HTML глобальный атрибут popover
Определение и применение
Глобальный атрибут popover превращает HTML-элемент во всплывающую область: по умолчанию
она скрыта, а после открытия отображается поверх обычного содержимого страницы. Например, кнопка
может открывать небольшую справку, не переводя пользователя на другую страницу.
Базовый показ и скрытие можно настроить прямо в HTML, без собственных обработчиков JavaScript.
Это механизм отображения и управления состоянием, а не отдельный тег и не готовый виджет меню. Атрибут можно задать подходящему по смыслу элементу: списку ссылок, разделу с настройками или блоку пояснения. Семантику содержимого, доступные названия и поведение сложных компонентов выбирает автор.
Поддержка браузерами
Спецификация: multipage
Поддерживается во всех основных браузерах с 2024 года.
Отдельные значения (1) поддерживаются не везде — смотрите таблицу.
| Возможность | Компьютеры | Мобильные | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
popover | 114 | 114 | 125 | 100 | 17 | 114 | 125 | 76 | 17 | 23.0 | 114 | 17 |
hint | 151 Версия 151 выпущена в 2026 г. Версия 133 выпущена в 2025 г. — Удалено в 151; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 499019927. | 151 Версия 151 выпущена в 2026 г. Версия 133 выпущена в 2025 г. — Удалено в 151; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 499019927. | 153 Версия 153 выпущена в 2026 г. Версия 149 выпущена в 2026 г. — Удалено в 153; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 2029974. | 135 Версия 135 выпущена в 2026 г. Версия 118 выпущена в 2025 г. — Удалено в 135; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 499019927. | preview | 151 Версия 151 выпущена в 2026 г. Версия 133 выпущена в 2025 г. — Удалено в 151; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 499019927. | 153 Версия 153 выпущена в 2026 г. Версия 149 выпущена в 2026 г. — Удалено в 153; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 2029974. | 101 Версия 101 выпущена в 2026 г. Версия 88 выпущена в 2025 г. — Удалено в 101; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 499019927. | 29.0 Версия 29.0 выпущена в 2025 г. — Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 499019927. | 151 Версия 151 выпущена в 2026 г. Версия 133 выпущена в 2025 г. — Удалено в 151; Частичная поддержка Примечание MDN (англ.) Implements an older version of the specification with inconsistent behaviors. See bug 499019927. | ||
поддерживаетсяс ограниченияминет поддержкинет данных≤31 — не позднее версии 31
Поддержку popover и распознавание режима hint можно проверить отдельно:
const supportsPopover = 'popover' in HTMLElement.prototype;
const probe = document.createElement('div');
probe.setAttribute('popover', 'hint');
const recognizesHint = supportsPopover && probe.popover === 'hint';
Распознавание hint ещё не гарантирует полную поддержку его поведения. Если браузер
поддерживает popover, но не hint, область работает как manual.
Поэтому у примера подсказки есть явная кнопка закрытия.
Без поддержки popover содержимое остаётся видимым, а кнопки с popovertarget
не работают. Можно сохранить обычный текст или использовать
<details>.
Не скрывайте важный текст через display: none без работающего способа показа.
Базовый синтаксис
<button type="button" popovertarget="delivery">
Условия доставки
</button>
<section id="delivery" popover aria-labelledby="delivery-title">
<h2 id="delivery-title">Доставка</h2>
<p>Заказы доставляются по будням с 10 до 18 часов.</p>
<button type="button" popovertarget="delivery" popovertargetaction="hide">
Закрыть
</button>
</section>
Атрибут popovertarget у
<button>
содержит значение id
целевой области без символа #. Цель должна находиться в том же дереве
документа, что и кнопка, и иметь атрибут popover. Такая связь также поддерживается
у <input type="button">.
У кнопки явно указан type="button", чтобы внутри формы она не стала кнопкой отправки.
Управляющую кнопку не помещают внутрь изначально скрытой панели: тогда до неё нельзя будет добраться.
Дополнительная кнопка закрытия внутри панели, напротив, полезна.
Попробуйте пример без JavaScript.
Значения атрибута
| Значение | Поведение |
|---|---|
auto | Поддерживает закрытие кликом снаружи и запросом закрытия, обычно клавишей Escape. Открытие другой независимой панели auto закрывает прежнюю; вложенные панели могут оставаться открытыми вместе. |
manual | Закрывается явной командой кнопки или вызовом API. Клик снаружи и Escape автоматически его не закрывают. Можно открыть несколько независимых панелей. |
hint | Режим подсказок: открытие не закрывает панели auto, но закрывает другие hint, кроме предков в цепочке подсказок. Поддерживает клик снаружи и запрос закрытия. Совместимость проверяется отдельно. |
Пустые записи popover и popover="" означают auto.
При отсутствии атрибута элемент вообще не является всплывающей областью. Неизвестное значение
обрабатывается как manual: например, popover="false" не отключает возможность.
Это перечислимый атрибут: его значение задаёт режим работы всплывающей области.
Показ и закрытие из HTML
Действие кнопки задаёт popovertargetaction. Оно не меняет режим самой области:
кнопка с hide может закрыть как auto, так и manual.
| Значение | Действие |
|---|---|
toggle | Открыть закрытую область или закрыть открытую. Используется при отсутствии атрибута и при неизвестном значении. |
show | Открыть область. Если она уже открыта, повторно переключать её не нужно. |
hide | Закрыть область. Если она уже закрыта, она остаётся закрытой. |
Слово manual не означает «обязательно написать JavaScript»:
пример с явным закрытием целиком работает через HTML.
Главное — предоставить пользователю понятный способ закрыть панель.
Автоматическое закрытие и вложенные панели
Закрытие при клике вне панели называют light dismiss — лёгким закрытием, без отдельной кнопки.
Для auto браузер учитывает связи между всплывающими областями. Например, внутри панели
фильтров можно открыть вложенное пояснение: открытие дочерней области не должно уничтожать её родителя.
Связь возникает, в частности, при вложении одного popover в другой или размещении управляющей кнопки
внутри открытого popover. В примере вложенности
используется явное вложение в DOM. Первое нажатие Escape закрывает дочернюю область,
следующее — родительскую. Клик в родительской панели за пределами дочерней закрывает только дочернюю.
Режим hint предназначен для пояснений, которые могут появиться поверх открытой панели
auto. Но сам атрибут не назначает реакцию на наведение или фокус и не создаёт
role="tooltip". Способ открытия и семантика подсказки — отдельная задача.
Более того, клик по внешней кнопке может закрыть auto как обычный клик снаружи;
это не противоречит правилу, что само открытие hint не закрывает auto.
В примере hint кнопка подсказки расположена внутри
основной панели, чтобы отдельно наблюдать взаимодействие режимов. В актуальной спецификации
цепочки auto и hint учитываются раздельно; старые реализации hint
могут иначе обрабатывать вложенные сочетания. Не переносите правила одного режима на другой.
Верхний слой и оформление
Открытая область попадает в верхний слой (top layer) — специальный слой отображения браузера
над обычными контекстами наложения. Поэтому высокий
z-index
обычного блока не перекрывает popover, а
overflow: hidden
у предка не обрезает открытую панель. Среди элементов самого верхнего слоя важен порядок их добавления.
DOM при этом не меняется: элемент остаётся потомком своего контейнера, сохраняет наследуемые стили
и путь распространения событий. Верхний слой не переносит элемент в конец body и не
освобождает от инертности предка. Внутри iframe верхний слой ограничен документом фрейма:
панель учебного примера не может выйти поверх всего сайта.
Браузер по умолчанию центрирует popover, задаёт рамку, фон и отступы. Связь с кнопкой сама по себе
не размещает панель рядом с ней.
Открытое состояние: :popover-open
Псевдокласс :popover-open выбирает открытую всплывающую область.
Закрытые popover скрыты браузером через
display: none.
Общее правило вроде [popover] { display: block; } может перебить скрытие и показать закрытую
панель прямо в документе. Задавайте нужный display через :popover-open.
Например, включим сеточную раскладку только для открытой панели:
#delivery:popover-open {
display: grid;
gap: 0.5rem;
}Фон и анимация
Псевдоэлемент ::backdrop позволяет оформить фон за открытой областью, но не делает интерфейс
модальным. Для привязки панели к кнопке существует CSS Anchor Positioning; его поддержку проверяют
отдельно. Синтаксис и варианты можно исследовать в
инструменте якорного позиционирования.
Для плавного входа и выхода недостаточно анимировать только прозрачность: закрытие переключает
display и удаляет элемент из верхнего слоя. Современный вариант использует переходы
display и overlay с allow-discrete, а начальный стиль входа —
@starting-style. Это отдельные возможности CSS с собственной совместимостью;
без их поддержки панель должна продолжать открываться и закрываться мгновенно.
Фокус, клавиатура и доступность
popovertarget связывает кнопку с панелью: браузер учитывает эту связь при переходе фокуса
и сообщает состояние раскрытия вспомогательным технологиям. Статический
aria-expanded="false" добавлять не нужно.
- Tab позволяет переходить к элементам панели и дальше по странице: фокус внутри не удерживается.
autofocusзадавайте только при необходимости сразу перейти к полю ввода. - Escape закрывает панели
autoиhint. При программном управлении проверяйте возврат фокуса и не забирайте его у выбранного пользователем элемента. - Дайте кнопке понятное название, а панели — заголовок. Связать панель с заголовком можно через
aria-labelledby, как в базовом примере. - Для обычного списка ссылок достаточно HTML-разметки.
role="menu"требует отдельной клавиатурной навигации.
Важная информация должна иметь понятный способ открытия. Само появление popover
не гарантирует, что скринридер озвучит его содержимое.
Управление через JavaScript
Методы вызывают у элемента с атрибутом popover, добавленного в документ:
const panel = document.querySelector('#delivery');
panel.showPopover(); // Показать.
panel.hidePopover(); // Скрыть.
panel.togglePopover(); // Переключить состояние.
panel.togglePopover(true); // Показать, если закрыта.
panel.togglePopover(false); // Скрыть, если открыта.
const isOpen = panel.matches(':popover-open'); // Открыта ли панель.
Свойство panel.popover хранит режим ('auto', 'manual',
'hint' или null при отсутствии атрибута), а не состояние видимости.
Его изменение само по себе не открывает панель.
Для проверки видимости используйте matches(':popover-open'), как в примере:
возвращаемое значение togglePopover() различается в старых и новых реализациях.
Один элемент нельзя одновременно открыть как popover и модальный диалог
или перевести в полноэкранный режим: такие вызовы могут привести к исключению.
События beforetoggle и toggle
Событие beforetoggle приходит перед изменением видимости, toggle — после него.
Их свойства oldState и newState содержат строки 'open' или
'closed'. Обработчики регистрируют на самой панели:
panel.addEventListener('beforetoggle', (event) => {
if (event.newState === 'open') {
// Подготовить содержимое до показа.
}
});
panel.addEventListener('toggle', (event) => {
console.log(event.oldState, event.newState);
});
Открытие можно отменить вызовом event.preventDefault() в beforetoggle.
Закрытие через это событие не отменяется. Событие toggle тоже не отменяемое; несколько
быстрых переключений могут объединиться в одно уведомление. Поэтому оно подходит для отражения
итогового состояния, но не для подсчёта каждого вызова метода.
Не отслеживайте состояние только обработчиком клика управляющей кнопки: панель может закрыться
через Escape, клик снаружи или открытие другой панели. В
примере API и событий сообщение обновляется через
toggle, а beforetoggle демонстрирует отмену открытия.
Типичные ошибки
popovertarget="#help"вместоpopovertarget="help", повторяющиесяidили цель безpopover.- Ожидание, что
popover="manual"закроется по Escape без отдельного обработчика. - Добавление
hiddenкpopover: это другой механизм скрытия, который может помешать показу через API. - Изменение только
displayвместо использования кнопки или API: визуальный показ не переводит элемент в открытое состояниеpopover. - Ожидание автоматического размещения у кнопки, автоматического наведения у
hintили готовой клавиатурной модели ARIA-меню. - Применение
aria-modal="true"к немодальной панели: атрибут сообщает неверную модель взаимодействия и не делает фон недоступным.
Спецификация
HTML Living Standard: popover.
Примеры, попробуйте сами
Примеры используют нативный Popover API браузера. В HTML-примерах без его поддержки панели будут обычными видимыми блоками. Для проверки Escape сначала установите фокус внутри результата.
Панель без JavaScript
Откройте справку кнопкой, затем закройте её повторным нажатием, кликом снаружи или Escape. Клавиша Tab позволяет перейти к кнопке внутри панели. Измените popovertarget и сравните его с id цели.
index.html
<button type="button" popovertarget="delivery">Условия доставки</button>
<p><label>Поле вне панели <input placeholder="Фон остаётся доступен"></label></p>
<section id="delivery" popover aria-labelledby="delivery-title">
<h2 id="delivery-title">Доставка</h2>
<p>Заказы доставляются по будням с 10 до 18 часов.</p>
<button type="button" popovertarget="delivery" popovertargetaction="hide">Закрыть</button>
</section>
Явное закрытие manual
Откройте панель и попробуйте кликнуть снаружи или нажать Escape: manual останется открытым. Закройте его кнопкой с popovertargetaction="hide". Замените режим на auto и сравните поведение.
index.html
<button type="button" popovertarget="note" popovertargetaction="show">Показать памятку</button>
<p><label>Поле вне панели <input placeholder="Можно продолжать работу"></label></p>
<section id="note" popover="manual" aria-labelledby="note-title">
<h2 id="note-title">Памятка</h2>
<p>Перед отправкой заказа проверьте адрес доставки.</p>
<button type="button" popovertarget="note" popovertargetaction="hide">Закрыть памятку</button>
</section>
Вложенные и независимые панели
Откройте фильтры, затем пояснение внутри них: обе панели останутся открыты. Закрывайте их клавишей Escape по очереди. Снова откройте фильтры и нажмите внешнюю кнопку доставки: независимая панель auto заменит фильтры. В style.css измените положение панелей.
index.html
<button type="button" popovertarget="filters">Фильтры</button>
<button type="button" popovertarget="delivery">Доставка</button>
<section id="filters" popover aria-labelledby="filters-title">
<h2 id="filters-title">Фильтры каталога</h2>
<p><label><input type="checkbox"> Только в наличии</label></p>
<button type="button" popovertarget="explanation">Что значит «в наличии»?</button>
<button type="button" popovertarget="filters" popovertargetaction="hide">Закрыть фильтры</button>
<section id="explanation" popover aria-labelledby="explanation-title">
<h2 id="explanation-title">Наличие товара</h2>
<p>Товар можно получить со склада без предзаказа.</p>
<button type="button" popovertarget="explanation" popovertargetaction="hide">Закрыть пояснение</button>
</section>
</section>
<section id="delivery" popover aria-labelledby="delivery-title">
<h2 id="delivery-title">Доставка</h2>
<p>Эта панель независима от фильтров.</p>
<button type="button" popovertarget="delivery" popovertargetaction="hide">Закрыть доставку</button>
</section>
style.css
/* Разводим панели по высоте, чтобы видеть родительскую и дочернюю одновременно. */
[popover] {
margin: 0;
max-width: calc(100vw - 4rem);
}
#filters,
#delivery {
inset: 4rem auto auto 1rem;
}
#explanation {
inset: 13rem auto auto 2rem;
}
Подсказка поверх auto
Откройте настройки и подсказку внутри них. В браузере с поддержкой hint подсказка не закрывает auto. Попробуйте Escape. Если hint не поддерживается, он работает как manual; используйте явную кнопку закрытия. Частичная реализация может отличаться в сложных сценариях.
index.html
<button type="button" popovertarget="settings">Настройки</button>
<section id="settings" popover="auto" aria-labelledby="settings-title">
<h2 id="settings-title">Настройки уведомлений</h2>
<p><label><input type="checkbox"> Присылать новости</label></p>
<button type="button" popovertarget="hint">О частоте писем</button>
<button type="button" popovertarget="settings" popovertargetaction="hide">Закрыть настройки</button>
<section id="hint" popover="hint" aria-labelledby="hint-title">
<h2 id="hint-title">Частота писем</h2>
<p>Не чаще одного письма в неделю.</p>
<button type="button" popovertarget="hint" popovertargetaction="hide">Закрыть подсказку</button>
</section>
</section>
style.css
/* Размещение позволяет наблюдать обе панели, не перекрывая кнопку подсказки. */
[popover] {
margin: 0;
max-width: calc(100vw - 4rem);
}
#settings {
inset: 3rem auto auto 1rem;
}
#hint {
inset: 13rem auto auto 2rem;
}
Методы и события Popover API
Нажмите . Откройте и закройте панель кнопками API; проверьте сообщение после Escape и клика снаружи. Включите запрет открытия: beforetoggle отменит показ через preventDefault(). Перезапустите пример для возврата в начальное состояние.
index.html
<p><label><input id="block" type="checkbox"> Запретить открытие</label></p>
<button id="show" type="button" popovertarget="panel" disabled>Показать через API</button>
<button id="toggle" type="button" popovertarget="panel" disabled>Переключить через API</button>
<p id="status" role="status">Запустите пример.</p>
<section id="panel" popover aria-labelledby="panel-title">
<h2 id="panel-title">Панель с событиями</h2>
<p>Состояние отслеживается независимо от способа закрытия.</p>
<button id="hide" type="button" autofocus>Закрыть через API</button>
</section>
main.js
const panel = document.querySelector('#panel');
const show = document.querySelector('#show');
const toggle = document.querySelector('#toggle');
const hide = document.querySelector('#hide');
const block = document.querySelector('#block');
const statusMessage = document.querySelector('#status');
let opener = null;
if (!('popover' in HTMLElement.prototype)) {
statusMessage.textContent = 'Popover API не поддерживается. Содержимое показано обычным разделом.';
hide.disabled = true;
} else {
show.disabled = false;
toggle.disabled = false;
statusMessage.textContent = 'Панель закрыта.';
// popovertarget связывает внешние кнопки с панелью: нажатие не считается
// кликом снаружи. Отменяем встроенное действие, поскольку вызываем API сами.
show.addEventListener('click', (event) => {
event.preventDefault();
opener = show;
panel.showPopover();
});
toggle.addEventListener('click', (event) => {
event.preventDefault();
opener = toggle;
panel.togglePopover();
});
hide.addEventListener('click', () => {
// При явном закрытии возвращаем фокус к последней кнопке открытия.
// Клик снаружи не должен отбирать фокус у выбранного пользователем поля.
panel.hidePopover();
if (opener) {
opener.focus();
}
});
panel.addEventListener('beforetoggle', (event) => {
if (event.newState === 'open' && block.checked) {
event.preventDefault();
statusMessage.textContent = 'Открытие отменено в beforetoggle.';
}
});
panel.addEventListener('toggle', (event) => {
statusMessage.textContent = event.newState === 'open' ? 'Панель открыта.' : 'Панель закрыта.';
});
}
Нажмите , чтобы запустить пример.