MUI Modal w React - kiedy wybrać Modal, a kiedy Dialog?

Bruno Krawczyk 15 lipca 2026
Mui modal z opcjami "Dodaj nowego przyjaciela" i "Utwórz grupę" jest widoczny na ekranie aplikacji Go-Dutch.

Spis treści

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.

Mui modal z pytaniem

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.

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

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

FAQ - Najczęstsze pytania

Modal sprawdzi się przy lightboksie, niestandardowej nakładce lub panelu ustawień, gdy potrzebujesz pełnej kontroli nad strukturą i wyglądem. Dialog będzie lepszy dla typowego formularza, potwierdzenia albo okna z tytułem, treścią i przyciskami.

W funkcji obsługującej onClose sprawdź drugi argument reason. Gdy jego wartość to backdropClick, możesz pominąć setOpen(false), aby przypadkowe kliknięcie nie spowodowało utraty danych. Użytkownik powinien nadal mieć przycisk Anuluj i zwykle możliwość zamknięcia okna klawiszem Escape.

Ogranicz wysokość kontenera na przykład przez maxHeight: calc(100vh - 32px) i dodaj overflowY: auto. Dla dłuższych formularzy rozważ Dialog z właściwościami fullWidth, maxWidth i scroll albo widok pełnoekranowy. Sprawdź interfejs przy szerokości około 320 px oraz przy powiększeniu tekstu.

Połącz aria-labelledby i aria-describedby z identyfikatorami nagłówka oraz opisu. Nie wyłączaj bez potrzeby automatycznego przenoszenia, wymuszania i przywracania fokusu. Dodaj widoczny przycisk zamknięcia z aria-label, na przykład informującym, że zamyka okno.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

dialog
react
material ui
dostępność
modal
Autor Bruno Krawczyk
Bruno Krawczyk
Mam na imię Bruno i od 8 lat zgłębiam tajniki programowania w ekosystemie .NET, chmury Azure oraz sztucznej inteligencji. Moja przygoda z technologią zaczęła się od ciekawości, jak złożone systemy mogą ułatwiać codzienne życie i rozwiązywać realne problemy. Dziś moją misją jest dzielenie się tą wiedzą, starając się przybliżyć nawet najbardziej skomplikowane zagadnienia w sposób zrozumiały i przystępny dla każdego. W moich artykułach na kursdotnet.pl skupiam się na praktycznych aspektach, analizuję najnowsze trendy i weryfikuję informacje, aby dostarczyć Wam treści, które są nie tylko dokładne i aktualne, ale przede wszystkim użyteczne w Waszej własnej ścieżce rozwoju technologicznego.

Udostępnij artykuł

Napisz komentarz