Strona główna / Artykuły

Sześć wbudowanych funkcji HTML, które zastępują popularne biblioteki interfejsu użytkownika w JavaScript

Dowiedz się, jak popovery, ekskluzywne informacje, okna dialogowe, Declarative Shadow DOM, fetchpriority oraz datalist zastępują własny JavaScript, a także jakie ograniczenia nadal mają każde z nich.

Wydawca: REACTAPP.TOP6 min czytania1277 słów

Źródła: HTML Features in 2026 That Most Devs Don’t Know Exist

Przez lata HTML zapewniał strukturę, a JavaScript – wszystkie funkcje: modala oznaczała bibliotekę React, podpowiedź – Popper.js lub Tippy, a komponenty renderowane na serwerze wymagały własnych skryptów. Tymczasem WHATWG HTML Living Standard oraz silniki przeglądarek dodawały wbudowane elementy, które obejmują wiele z tych przypadków za pomocą kilku atrybutów, redukując ilość kodu i rozmiar plików przy jednoczesnym zapewnieniu dostępności domyślnie. Ten przewodnik omawia sześć z nich, niezbędne tagi oraz sytuacje, w których nadal potrzebny jest CSS lub JavaScript. Sprawdź zgodność przeglądarek z Twoją grupą odbiorców, zanim użyjesz rozwiązania awaryjnego.

1. Okna powiadomień z atrybutem popover

Wskazówki i menu tradycyjnie wymagały radzenia sobie z kontekstami układu z-index oraz ręcznego pisania obsługi kliknięć poza elementem. Dzięki API Popover każdy element posiadający atrybut popover jest przenoszony na najwyższy poziom po otwarciu, powyżej całej zwykłej treści, niezależnie od wartości z-index. Przycisk, którego atrybut popovertarget określa wartość id elementu, steruje jego otwieraniem i zamykaniem:

<!-- 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>

Bez żadnego JavaScriptu otrzymujemy:

  • Deklaracyjne sterowanie: przycisk otwiera i zamyka okno informacyjne.
  • Lekkie zamknięcie: kliknięcie poza obszarem lub naciśnięcie klawisza Escape zamyka je. Dotyczy to domyślnego trybu popover="auto"; w trybie popover="manual" decyzja o zamknięciu należy do użytkownika.
  • Brak konfliktów układu: otwarte okno informacyjne jest renderowane na najwyższym poziomie, powyżej wszystkiego innego.

Dwa ograniczenia: API kontroluje widoczność i układ elementów, a nie ich położenie, więc aby przymocować menu do jego wyzwalacza, nadal potrzebny jest CSS (klasyczne pozycjonowanie lub nowsze, mniej powszechnie wspierane pozycjonowanie typu anchor). Ponadto element popover nie jest modalny i nie blokuje fokusa, więc do potwierdzeń należy używać tagu dialog.

2. Wyłączne akordeony z detalami i nazwą

Tagi details i summary od dawna umożliwiają tworzenie sekcji, które można składać, bez użycia JavaScripta. Nowością jest to, że elementy details dzielące się tą samą nazwą (name) tworzą grupę, w której tylko jeden z nich może być otwarty, podobnie jak w klasycznym akordeonie.

<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>

Otwarcie jednego elementu zakończa otwieranie wszystkich innych elementów o nazwie name="faq", bez konieczności używania słuchaczy, hooki stanu czy zmiany klas. Przeglądarki bez obsługi pola name po prostu pozwalają na otwarcie kilku elementów, co stanowi elegancką alternatywę.

3. Dostępne modale z dialogiem i ::backdrop

Spersonalizowane nakładki typu div często nie przechodzą audytów dostępności, ponieważ prawidłowe modal musi utrzymywać fokus w swoim wnętrzu, zablokować stronę za nim i po tym przywrócić fokus do elementu, który je uruchomił. Element dialog zajmuje się tym zadaniem. Poniżej formularz z method="dialog" zamyka dialog po naciśnięciu dowolnego przycisku, a value naciśniętego przycisku staje się wartością returnValue dialogu:

<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>

Zaciemniona nakładka to pseudo-element ::backdrop, stylizowany za pomocą zwykłego CSS:

/* Styling the native browser backdrop */
dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
}

showModal() umieszcza okno dialogowe na górnej warstwie, czyni resztę strony nieruchomą, utrzymuje fokus wewnątrz niego i umożliwia zamknięcie klawiszem Escape; po zamknięciu obecne przeglądarki przywracają fokus do wcześniej wybranego elementu. show() natomiast otwiera okno w trybie niemodalnym, bez tych zabezpieczeń. W React należy wywołać showModal() za pośrednictwem ref zamiast inline onclick.

4. Komponenty webowe renderowane na serwerze z deklaratywnym Shadow DOM

Kiedyś Shadow DOM wymagał JavaScriptu po stronie klienta (element.attachShadow({ mode: 'open' })), więc komponenty webowe renderowane na serwerze lub generowane statycznie nie miały zamkniętego markupu, dopóki nie uruchomiono skryptów, co powodowało chwilowe braki stylizacji i zmiany układu. Deklaratywny Shadow DOM rozwiązuje ten problem: template z atrybutem shadowrootmode wewnątrz elementu hosta opisuje drzewo cienia w formacie 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>

Parser przekształca szablon w korzeń cieniowy na elementach user-card przed renderowaniem, dzięki czemu style i markup o ograniczonym zasięgu są widoczne od razu po narysowaniu elementu. Uwaga: dzieje się to tylko podczas parsowania HTML. Markup wstawiony później za pomocą innerHTML nie tworzy korzenia cieniowego; dynamiczne wstawianie wymaga użycia takich API jak setHTMLUnsafe(), więc należy sprawdzić aktualne wsparcie.

5. Priorytetyzowanie kluczowych zasobów za pomocą fetchpriority

loading="lazy" oraz async/defer nie mogą określić, które z wczesnych zasobów są najważniejsze. Gdy na stronie znajduje się kilka obrazów, obraz główny poza obszarem natychmiastowej widoczności powinien mieć pierwszeństwo przed odznakami i ikonami. fetchpriority dostarcza schedulerowi sieci takiej wskazówki:

<!-- 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>

To może poprawić Core Web Vitals bez ingerencji w logikę aplikacji. Jest to sugestia, a nie polecenie, a oznaczenie wielu zasobów jako high unieważnia ten efekt. Ponadto nigdy nie należy ładować obrazu LCP w trybie lazy-loading.

6. Rodzime sugestie z datalist

wiele projektów dodaje ciężki komponent autouzupełniania tylko po to, by sugerować wartości przy jednoczesnym umożliwieniu wpisywania dowolnego tekstu. datalist robi to w sposób natywny: wystarczy powiązać go za pomocą atrybutu list pola wejściowego, a jego opcje staną się sugestiami.

<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>

Przeglądarka renderuje i filtrowa listę, obsługuje nawigację klawiaturą oraz przestrzega stylu platformy. Kompromisem jest brak kontroli: stylizacja jest minimalna, zachowanie różni się w zależności od przeglądarek i urządzeń mobilnych, a rozbudowane opcje są niemożliwe do zaimplementowania. Idealne dla prostych pól typu „wybierz lub wpisz”; branded combobox nadal wymaga osobnego komponentu.

Funkcja natywna w porównaniu ze starym podejściem

  • Podpowiedzi i menu: popover zamiast biblioteki do pozycjonowania, plus obsługa kliknięć poza elementem i klawisza Escape (sam pozycjonowanie nadal pochodzi z CSS).
  • Akordony: elementy details dzielące się wartością name zamiast logiki zarządzania stanem i przełączaniem w JavaScript.
  • Okna modalne: dialog z metodą showModal() i właściwością ::backdrop zamiast niestandardowej warstwy nakładającej się z ręcznie pisanym zarządzaniem fokusem.
  • Komponenty renderowane na serwerze w formie zamkniętych struktur: template shadowrootmode zamiast wywołań attachShadow() dostępnych tylko na stronie klienta.
  • Priorytety ładowania: fetchpriority zamiast ręcznych trików preładowania lub ustalania kolejności ładowania za pomocą skryptów.
  • Sugestie dotyczące wprowadzania danych: datalist zamiast niestandardowego widgetu autodopasowywania w prostych przypadkach.
  • Aby zapoznać się z szerszym przeglądem funkcji platformy, które mogą zastąpić zależności, sprawdź nasz przegląd API przeglądarki natywnej zastępujących popularne pakiety npm.

    Główne wnioski

    • Przeglądarki dostarczają teraz funkcjonalności, które wcześniej wymagały bibliotek, często z wbudowanym obsługą fokusa i możliwością zamknięcia naciśnięciem klawisza Escape.
    • Natywne rozwiązania nie oznaczają pełnej funkcjonalności: elementy typu popover wymagają CSS do prawidłowego umieszczenia, datalist oferuje ograniczone możliwości stylizacji, a Declarative Shadow DOM działa tylko w momencie analizy kodu.
    • Zanim dodasz zależność interfejsową, sprawdź, czy jakiś element lub atrybut może zaspokoić rzeczywiste potrzeby w obsługiwanych przez ciebie przeglądarkach.

    Powiązane materiały

  • Siedem własności JavaScript, które zastępują zależności utility — Jak Temporal, wykorzystując deklaracje, operacje Map upsert, Math.sumPrecise, pomocniki iteratorów, metody Set oraz Promise.withResolvers, eliminuje typowe zbędne elementy w JavaScript.
  • Od „div soup” do znaczącego markupu: praktyczny przewodnik po semantycznym HTML — Dowiedz się, dlaczego ogólne elementy div psują dostępność, możliwości indeksowania i łatwość konserwacji, jakie elementy semantyczne należy zamiast nich używać oraz jak przeprojektować rzeczywisty komponent karty.