Portale dla modali i podpowiedzi
Użyje Pan/Pani ReactDOM.createPortal do renderowania elementów potomnych w innym węźle DOM, co umożliwi tworzenie modali i podpowiedzi wychodzących poza kontenery overflow:hidden.
Portale dla modali i podpowiedzi to bezpłatna lekcja Frontend Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Frontend Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Frontend Academy zawiera 4 lekcji w sumie.
Problem z ucieczką z kontenera
Modale i tooltipy muszą być renderowane u góry DOM, poza ograniczeniami overflow:hidden, stosami z-index i kontekstami zakotwiczonymi przez transform ich rodzica. Rozwiązaniem są portale.
API createPortal
createPortal(children, container) renderuje children w elemencie container (dowolnym węźle DOM), zachowując je logicznie jako dzieci komponentu React na potrzeby obsługi zdarzeń i kontekstu.
import { createPortal } from 'react-dom';
function Modal({ children, onClose }) {
return createPortal(
<div className="modal-backdrop" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
{children}
</div>
</div>,
document.body
);
}Kontenery portali
Typowe miejsca docelowe to: document.body, przeznaczony do tego element #modal-root w pliku index.html lub kontener wskazywany przez ref i tworzony na żądanie.
<!-- index.html -->
<div id="root"></div>
<div id="modal-root"></div>
// component:
const modalRoot = document.getElementById('modal-root');
return createPortal(<div>...</div>, modalRoot);Dlaczego nie renderować bezpośrednio?
Jeśli rodzic ma overflow: hidden, modal potomny zostanie przycięty. Jeśli rodzic ma transform: scale, pozycjonowanie fixed modalu stanie się względne względem rodzica. Portale pozwalają uniknąć obu tych problemów.
Zdarzenia nadal propagują się w górę
Mimo renderowania w innym miejscu DOM zdarzenia React propagują się przez drzewo komponentów, a nie przez drzewo DOM. Kliknięcie w portalu nadal dociera do procedur obsługi onClick w nadrzędnych komponentach React.
Zamykanie po kliknięciu nakładki
Należy zatrzymać propagację zdarzeń w treści modalu, aby kliknięcia wewnątrz nie zamykały modalu.
function Modal({ onClose, children }) {
return createPortal(
<div className="backdrop" onClick={onClose}>
<div className="content" onClick={e => e.stopPropagation()}>
{children}
</div>
</div>,
document.body
);
}Zamykanie klawiszem Escape
Należy dodać nasłuchiwanie zdarzenia keydown, gdy modal jest otwarty, i usunąć je podczas odmontowywania.
useEffect(() => {
const onKey = (e) => { if (e.key === 'Escape') onClose(); };
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [onClose]);Zarządzanie fokusem w portalach
Po otwarciu modalu należy przenieść fokus do jego wnętrza, uwięzić fokus do chwili zamknięcia, a następnie przywrócić fokus elementowi, który otworzył modal. Warto użyć biblioteki takiej jak focus-trap-react, aby nie implementować tego samodzielnie.
Natywny element dialog
Element <dialog> w HTML natywnie obsługuje pozycjonowanie modalu, tło, pułapkę fokusu i zamykanie klawiszem Escape. W przypadku większości modali jest lepszym punktem wyjścia niż portal.
function Modal({ open, onClose, children }) {
const ref = useRef(null);
useEffect(() => {
if (open) ref.current?.showModal();
else ref.current?.close();
}, [open]);
return (
<dialog ref={ref} onClose={onClose}>
{children}
</dialog>
);
}Tooltipy i popovery
Tooltipy są pozycjonowane względem elementu kotwiczącego. Portal pozwala im wyjść poza konteksty stosu. Można połączyć go z floating-ui, aby obsługiwać wykrywanie kolizji, zmianę strony i pozycjonowanie.
import { useFloating, autoUpdate } from '@floating-ui/react';
function Tooltip({ children, content }) {
const { refs, floatingStyles } = useFloating({ whileElementsMounted: autoUpdate });
const [open, setOpen] = useState(false);
return (
<>
<button ref={refs.setReference} onMouseEnter={() => setOpen(true)} onMouseLeave={() => setOpen(false)}>
{children}
</button>
{open && createPortal(
<div ref={refs.setFloating} style={floatingStyles}>{content}</div>,
document.body
)}
</>
);
}Uwaga dotycząca SSR
document nie istnieje po stronie serwera. Należy albo renderować wyłącznie po stronie klienta (sprawdzając typeof window), albo użyć dynamic z ssr:false w Next.js.
Dostępność: aria-modal
Kontenery modali powinny mieć role="dialog", aria-modal="true" oraz aria-labelledby wskazujące nagłówek modalu. Można też użyć natywnego <dialog>.
Szybki test
Dlaczego w przypadku modali należy używać createPortal zamiast renderować je bezpośrednio w drzewie komponentów?
Podsumowanie: portale
createPortal(children, container) renderuje elementy DOM w innym miejscu, zachowując logiczne drzewo React. Rozwiązuje problemy z wydostawaniem się poza overflow, transform i z-index. Zdarzenia nadal propagują się przez drzewo React. Należy dodać zamykanie klawiszem Escape i zarządzanie fokusem. Natywny <dialog> obsługuje znaczną część tych funkcji w przypadku modali. Tooltipy można połączyć z floating-ui. Nie należy zapominać o SSR (sprawdzaniu typeof window).
Ucz się HTML dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 41
- Lekcje
- 163
Często zadawane pytania
Czy lekcja „Portale dla modali i podpowiedzi” jest bezpłatna?
Tak — pełny tekst „Portale dla modali i podpowiedzi” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Frontend Academy, przejdź na CoddyKit PRO. Kurs Frontend Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Portale dla modali i podpowiedzi”?
Użyje Pan/Pani ReactDOM.createPortal do renderowania elementów potomnych w innym węźle DOM, co umożliwi tworzenie modali i podpowiedzi wychodzących poza kontenery overflow:hidden. Ćwiczysz Frontend Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Frontend Academy?
Nie wymagamy żadnego doświadczenia. Frontend Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Portale dla modali i podpowiedzi”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Frontend Academy?
Tak. Każda lekcja Frontend Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Komponenty złożone z Context
- Wzorce Render Props i HOC
- Portale dla modali i podpowiedzi
- Granice błędów