Gdy użytkownik ma potwierdzić usunięcie danych, uzupełnić krótki formularz albo zobaczyć szczegóły bez opuszczania strony, dobrze zaprojektowane okno modalne potrafi znacznie uprościć interakcję. Komponent określany jako mui modal daje w React gotową obsługę tła, fokusu, blokady przewijania i klawiatury, ale wymaga świadomego użycia. Pokażę, kiedy sięgać po Modal, kiedy lepszy będzie Dialog oraz jak uniknąć typowych problemów z dostępnością i responsywnością.
Najważniejsze decyzje przy wdrażaniu modala w React
- Modal jest niskopoziomowym komponentem do budowania własnych okien, lightboxów i nakładek.
- Do klasycznego formularza lub potwierdzenia akcji zwykle lepiej wybrać Dialog.
- Stan widoczności kontrolują przede wszystkim właściwości open i onClose.
- Poprawna obsługa fokusu i ARIA jest równie ważna jak wygląd.
- Na urządzeniach mobilnych trzeba ograniczyć wysokość okna i zaplanować przewijanie treści.

Co właściwie daje Modal w MUI
Modal wyświetla zawartość nad głównym interfejsem aplikacji i zwykle dodaje półprzezroczyste tło, tak zwany backdrop. Elementy znajdujące się pod nim przestają być dostępne, a użytkownik powinien skupić się na jednej decyzji lub zadaniu.
Komponent zajmuje się również blokadą przewijania strony, przeniesieniem fokusu do otwartego okna oraz przywróceniem go po zamknięciu. To ważne, bo sam CSS z właściwością z-index nie tworzy jeszcze poprawnego modala. Bez zarządzania fokusem użytkownik klawiatury może przypadkiem poruszać się po elementach ukrytych pod nakładką.
W praktyce używam tego komponentu głównie wtedy, gdy potrzebuję większej kontroli nad wyglądem i strukturą zawartości. Dobrym przykładem jest lightbox ze zdjęciem, niestandardowy panel ustawień albo własny overlay, który nie pasuje do typowego okna dialogowego.
Modal czy Dialog i który komponent wybrać
Najczęstszy błąd polega na użyciu najniższego poziomu API do zadania, które ma już gotowe rozwiązanie. Dokumentacja MUI traktuje Modal jako fundament wykorzystywany także przez Dialog, Drawer, Menu i Popover. Dlatego do klasycznego okna z tytułem, treścią i przyciskami najczęściej wybieram Dialog.
| Potrzeba | Lepszy wybór | Dlaczego |
|---|---|---|
| Potwierdzenie usunięcia rekordu | Dialog | Ma gotowe elementy tytułu, treści i akcji. |
| Formularz logowania | Dialog | Łatwiej zachować spójną strukturę i obsługę przycisków. |
| Podgląd zdjęcia | Modal | Można swobodnie zaprojektować zawartość i tło. |
| Niestandardowa nakładka | Modal | Daje większą kontrolę nad pozycjonowaniem i komponentem wewnętrznym. |
| Boczny panel nawigacyjny | Drawer | Komponent jest przeznaczony do interfejsu wysuwanego z krawędzi. |
Moja praktyczna zasada jest prosta. Jeżeli okno ma odpowiadać na pytanie albo zebrać dane, zaczynam od Dialog. Po Modal sięgam wtedy, gdy gotowa semantyka dialogu ogranicza projekt lub gdy buduję komponent bardziej zbliżony do warstwy prezentacyjnej niż formularza.
Jak zbudować pierwszy modal w React
W projekcie potrzebujesz pakietu Material UI oraz zależności odpowiedzialnych za style. W istniejącej aplikacji React najczęściej wystarczy instalacja @mui/material, @emotion/react i @emotion/styled.
npm install @mui/material @emotion/react @emotion/styledMinimalny komponent może wyglądać tak:
import { useState } from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Modal from '@mui/material/Modal';
import Typography from '@mui/material/Typography';
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 'min(520px, calc(100% - 32px))',
bgcolor: 'background.paper',
borderRadius: 2,
boxShadow: 24,
p: 3,
};
export default function DetailsModal() {
const [open, setOpen] = useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
return (
<>
Szczegóły zamówienia
Zamówienie zostało przygotowane do wysyłki.
>
);
}Najważniejsze są tutaj trzy rzeczy. open określa, czy okno jest widoczne, onClose reaguje na próbę zamknięcia, a pojedyncze dziecko modala, w tym przypadku Box, zapewnia właściwy kontener dla zawartości. Szerokość ograniczona funkcją min() pozwala uniknąć poziomego przewijania na telefonie.
Jak kontrolować zamykanie i stan komponentu
Modal może zostać zamknięty przez przycisk, klawisz Escape albo kliknięcie w backdrop. Właściwość onClose otrzymuje drugi argument, który pozwala rozpoznać przyczynę zamknięcia.
const handleClose = (event, reason) => {
if (reason === 'backdropClick') {
return;
}
setOpen(false);
};Takie zachowanie ma sens przy formularzu, w którym przypadkowe kliknięcie poza oknem mogłoby spowodować utratę danych. Nie blokowałbym jednak zamknięcia bez wyraźnej potrzeby. Użytkownik powinien mieć dostęp do przycisku Anuluj i zwykle także do klawisza Escape.
Stan warto trzymać tam, gdzie faktycznie znajduje się logika interfejsu. Jeśli modal otwiera tabela, komponent nadrzędny może przechowywać identyfikator wybranego rekordu. Dzięki temu okno nie musi znać całej struktury strony, a jego ponowne użycie jest prostsze.
const [selectedId, setSelectedId] = useState(null);
const openDetails = (id) => setSelectedId(id);
const closeDetails = () => setSelectedId(null);
Unikam też otwierania kilku modalów jednocześnie. Zagnieżdżenie jednego okna może być uzasadnione, ale trzy warstwy z backdropami szybko prowadzą do problemów z fokusem, zamykaniem i orientacją użytkownika.
Formularze i responsywna zawartość
Krótki formularz, na przykład zmiana nazwy projektu, dobrze działa w modalu. Przy dłuższych formularzach trzeba już pilnować wysokości, kolejności fokusu i zachowania przycisków na małym ekranie. Samo zmniejszenie fontu nie rozwiązuje problemu.
Edytuj projekt
Jeżeli treści jest dużo, rozważ użycie komponentu Dialog z właściwościami fullWidth, maxWidth i scroll. Dla telefonu często sprawdza się pełnoekranowy dialog, bo użytkownik dostaje więcej miejsca na klawiaturę ekranową i nie musi przewijać małego panelu.
W aplikacjach produkcyjnych testuję modal przynajmniej w szerokości około 320 px, na dużym monitorze oraz przy powiększeniu tekstu w przeglądarce. To szybko ujawnia zbyt szerokie przyciski, ucięte komunikaty i problemy z zawartością, która nie ma własnego przewijania.
Dostępność nie kończy się na aria-label
Każde okno powinno mieć czytelny tytuł i, jeśli to potrzebne, opis. W tym celu łączę właściwości aria-labelledby i aria-describedby z identyfikatorami nagłówka oraz tekstu opisowego.
Usunąć projekt?
Tej operacji nie można cofnąć.
Nie wyłączaj bez potrzeby disableAutoFocus, disableEnforceFocus ani disableRestoreFocus. Te właściwości mogą być przydatne w nietypowych integracjach, lecz domyślna obsługa fokusu jest ważna dla osób korzystających z klawiatury i czytników ekranu.
Dodaj też widoczny przycisk zamknięcia, szczególnie gdy okno zawiera dużo treści. Ikona sama w sobie nie zawsze jest zrozumiała, dlatego przycisk powinien mieć aria-label, na przykład „Zamknij okno”. Przy akcjach destrukcyjnych opis przycisku powinien mówić, co się wydarzy, zamiast ograniczać się do słowa „OK”.
Stylowanie, portal i wydajność
Zawartość modala jest domyślnie renderowana przez portal, czyli poza zwykłą hierarchią DOM komponentu nadrzędnego, zwykle bezpośrednio w body. Dzięki temu modal nie przegrywa walki z overflow i lokalnymi indeksami z-index kontenerów.
Jeśli aplikacja korzysta z renderowania po stronie serwera, portal wymaga dodatkowej uwagi. W określonych przypadkach można użyć disablePortal albo własnego container, ale najpierw trzeba sprawdzić, czy problem rzeczywiście wynika z miejsca renderowania. Zbyt szybkie wyłączenie portalu często tworzy nowe kłopoty z warstwami.
Zamknięta zawartość jest standardowo odmontowywana. To korzystne, gdy modal zawiera ciężki komponent, ale może resetować stan formularza przy każdym otwarciu. W takim przypadku przydaje się keepMounted, choć używałbym go tylko wtedy, gdy testy pokażą realną potrzebę, a nie jako domyślną optymalizację.
Podczas stylowania zwróć uwagę na kontrast backdropu, promień zaokrąglenia, odstępy i maksymalną wysokość. Efekt powinien jasno oddzielać aktywną warstwę od tła, ale nie przytłaczać całej aplikacji. W mojej praktyce lepiej działa prosty panel z dobrą hierarchią niż efektowna animacja, która opóźnia dostęp do treści.
Dobre okno modalne zaczyna się od jednej decyzji
Przed implementacją odpowiedz sobie, czy użytkownik naprawdę musi zostać zatrzymany. Jeśli informację można pokazać w miejscu, komunikacie lub panelu bocznym, modal będzie niepotrzebnym przerwaniem pracy. Najlepiej sprawdza się przy krótkiej, ważnej interakcji, której nie warto obsługiwać przez zmianę całej strony.
Do własnych nakładek wybierz Modal, do typowych formularzy i potwierdzeń zacznij od Dialog, a na telefonie zaplanuj przewijanie lub widok pełnoekranowy. Gdy dopilnujesz fokusu, opisów ARIA, jasnych przycisków i kontrolowanego stanu, komponent będzie nie tylko estetyczny, ale też przewidywalny dla wszystkich użytkowników.
