Шість вбудованих функцій HTML, які замінюють поширені бібліотеки UI на JavaScript
Дізнайтеся, як popover, ексклюзивні деталі, діалогові вікна, Declarative Shadow DOM, fetchpriority та datalist замінюють власний JavaScript, а також які обмеження все ще існують у кожному з них.
Джерела: HTML Features in 2026 That Most Devs Don’t Know Exist
Протягом багатьох років HTML забезпечував структуру, а JavaScript — усю поведінку: модальне вікно означало використання бібліотеки React, підказка — Popper.js або Tippy, а компоненти, генеровані на сервері, вимагали власних скриптів. У той же час стандарт HTML Living Standard від WHATWG та движки браузерів додали вбудовані елементи, які покривають багато з цих випадків за допомогою кількох атрибутів, скорочуючи обсяг коду та розмір пакетів, водночас забезпечуючи належну доступність за замовчуванням. У цьому посібнику розглядаються шість таких елементів, маркап, необхідний для кожного з них, та ситуації, коли все ще потрібні CSS або JavaScript. Перед використанням альтернативних рішень переконайтеся у підтримці цих функцій вашою аудиторією браузерами.
1. Поп-вікна з атрибутом popover
Підказки та меню традиційно вимагали боротьби з контекстами накладання z-index та ручного створення обробників подій для кліків поза елементом. Завдяки API Popover будь-який елемент, який має атрибут popover, під час відкриття переміщується на верхній рівень, над усім звичайним вмістом, незалежно від значення z-index. Кнопка, у якої атрибут popovertarget вказує на id елемента, керує його відкриттям та закриттям:
<!-- The Trigger -->
<button popovertarget="my-menu">Toggle Menu</button>
<!-- The Popover Content -->
<div id="my-menu" popover>
<p>I am natively managed! Press ESC or click outside to close me.</p>
</div>
Без використання JavaScript отримуємо:
- Декларативне керування: кнопка відкриває та закриває підказку.
- Просте закриття: клік поза елементом або натискання клавіші Escape закриває підказку. Це стосується стандартного режиму
popover="auto"; у режиміpopover="manual"закриття залежить від користувача. - Відсутність конфліктів накладання: відкрита підказка відображається на верхньому рівні над усім іншим.
Два обмеження: API контролює видимість та викладання елементів, але не їх розташування, тому для прив’язки меню до його спускача все одно потрібен CSS (класичне позиціонування або новіший, менш поширений спосіб позиціонування за прив’язкою). Крім того, поп-овер не є модальним та не утримує фокус, тому для підтверджень використовуйте dialog.
2. Ексклюзивні акордіони з деталями та назвою
details та summary вже давно забезпечують можливість складання розділів без використання JavaScript. Новий елемент — details, які мають спільну назву name, утворюють групу, в якій може бути відкритий лише один елемент, як у класичному акордіоні.
<details name="faq">
<summary>What is modern HTML?</summary>
<p>A living standard evolving directly inside browser engines.</p>
</details>
<details name="faq">
<summary>Do I still need JavaScript?</summary>
<p>Much less of it than you used to!</p>
</details>
<details name="faq">
<summary>Is this supported natively?</summary>
<p>Yes, across all major modern browser engines.</p>
</details>
Відкриття одного запитання закриває будь-які інші відкриті елементи з name="faq", без використання слухачів, хуків стану чи зміни класів. Браузери без підтримки name просто дозволяють мати кілька відкритих елементів, що є гарним альтернативним рішенням.
3. Доступні модал-вікна з dialog та ::backdrop
Самостійно створені накладки з div часто провалюють перевірки на доступність, оскільки правильне модал-вікно має утримувати фокус всередині себе, блокувати сторінку позаду нього та після цього повертати фокус на елемент, який його відкрив. Елемент dialog вирішує цю проблему. Нижче форма з параметром method="dialog" закриває діалогове вікно при натисканні будь-якої кнопки, а значення value натиснутої кнопки стає значенням returnValue діалогового вікна:
<dialog id="user-modal">
<h2>Confirm Action</h2>
<p>Are you sure you want to delete this repository?</p>
<!-- A form inside a dialog with method="dialog" closes it automatically -->
<form method="dialog">
<button value="cancel">Cancel</button>
<button value="confirm">Delete</button>
</form>
</dialog>
<button onclick="document.getElementById('user-modal').showModal()">
Open Modal
</button>
Затемнена накладка — це псевдоелемент ::backdrop, який стилізується за допомогою звичайного CSS:
/* Styling the native browser backdrop */
dialog::backdrop {
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
}
showModal() розміщує діалог у верхньому шарі, робить решту сторінки нерухомою, зберігає фокус всередині неї та дозволяє закрити його за допомогою клавіші Escape; після закриття сучасні браузери повертають фокус до елемента, який був активним раніше. На відміну від цього, show() відкриває діалог у немодальному режимі без цих захистів. У React слід викликати showModal() через ref замість вбудованого onclick.
4. Веб-компоненти, генеровані на сервері, з декларативним Shadow DOM
Раніше для роботи Shadow DOM була необхідна JavaScript-логіка на клієнтській стороні (element.attachShadow({ mode: 'open' })), тому веб-компоненти, генеровані на сервері чи статично, не мали інкапсульованої структури до запуску скриптів, що спричиняло миттєві зміни вигляду та макету без налаштувань стилів. Декларативний Shadow DOM вирішує цю проблему: template із параметром shadowrootmode всередині елемента-хоста описує структуру тіньового дерева у форматі HTML:
<user-card>
<template shadowrootmode="open">
<style>
/* Styles here stay encapsulated inside this component */
h3 { color: #3b82f6; font-family: sans-serif; }
</style>
<h3>Jane Doe</h3>
<p>Senior Frontend Engineer</p>
</template>
</user-card>
Парсер перетворює шаблон на тіньовий корень у елементі user-card перед відображенням, тож обмежені за межами елемента стилі та маркап з’являються відразу після намальовування елемента. Увага: це відбувається лише під час парсингу HTML. Маркап, доданий пізніше за допомогою innerHTML, не створює тіньового кореня; для динамічного додавання потрібні API на кшталт setHTMLUnsafe(), тож перевірте поточну підтримку.
5. Пріоритезація критичних ресурсів за допомогою fetchpriority
loading="lazy" та async/defer не можуть визначити, які ресурси мають найвищий пріоритет. Якщо кілька зображень розташовані вгорі сторінки, зображення-герой після процесу Largest Contentful Paint (LCP) має мати пріоритет перед індикаторами та іконками. fetchpriority надає мережевому планувальнику цю інформацію:
<!-- Critical LCP Image: Load this immediately! -->
<img src="hero-banner.webp" fetchpriority="high" alt="Product Hero">
<!-- Lower priority images -->
<img src="avatar.webp" fetchpriority="low" alt="User avatar">
<!-- Critical JavaScript bundle -->
<script src="app.js" fetchpriority="high"></script>
Це може покращити показники Core Web Vitals без змін у логіці додатку. Це лише порада, а не команда, і позначення багатьох ресурсів як high скасовує цю перевагу. Також ніколи не використовуйте стратегію lazy-load для зображення LCP.
6. Вбудовані пропозиції за допомогою datalist
У багатьох проектах додається складний компонент автодоповнення лише для пропонування значень під час введення вільного тексту. datalist робить це вбудовано: його потрібно під’єднати за допомогою атрибута list елемента введення, і його опції стануть пропозиціями.
<label for="framework">Choose or type a framework:</label>
<input list="frameworks" id="framework" name="framework" placeholder="e.g. Next.js">
<datalist id="frameworks">
<option value="Next.js"></option>
<option value="SvelteKit"></option>
<option value="Nuxt.js"></option>
<option value="Astro"></option>
<option value="Remix"></option>
</datalist>
Браузер відображає та фільтрує список, керує навігацією за допомогою клавіатури та дотримується стилю платформи. Ціною є обмеження у контролі: стилізація є мінімальною, поведінка відрізняється між браузерами та пристроями мобільної версії, а розширені опції неможливі. Ідеально підходить для простих полів типу „виберіть або введіть“; для стилізованих комбоксів все одно потрібен окремий компонент.
Вбудована функція проти старого підходу
- Підказки та меню: використання
popoverзамість бібліотек для позиціонування, а також обробка кліків поза елементом та натискання клавіші Escape (саме позиціонування все ще здійснюється за допомогою CSS). - Аккордіони: елементи
details, які мають спільне значенняname, замість логіки керування станом та перемиканням у JavaScript. - Модальні вікна: використання
dialogз методамиshowModal()та::backdropзамість власного оверлею із ручним керуванням фокусом. - Компоненти, генеровані на сервері: використання параметра
template shadowrootmodeзамість викликівattachShadow(), які діють лише на клієнтській стороні. - Пріоритети завантаження: використання параметра
fetchpriorityзамість ручних методів попереднього завантаження чи визначення порядку завантаження через скрипти.
datalist замість власного віджета автодоповнення для простих випадків.Щоб дізнатися більше про функції платформи, які можуть замінити залежності, перегляньте наш огляд нативних API браузера, які замінюють популярні пакети npm.
Основні висновки
- Браузери тепер мають функціонал, який раніше вимагав бібліотек, часто з вбудованою обробкою фокусу та можливістю закриття клавішею Escape.
- Нативний формат не означає повноти: поп-апи потребують CSS для розташування,
datalistпропонує обмежені можливості стилізації, а Declarative Shadow DOM працює лише під час парсингу. - Перш ніж додавати залежність інтерфейсу, перевірте, чи певний елемент або атрибут може задовольнити ваші реальні потреби у підтримуваних браузерах.