Przejdź do treści

Dialog

Okno nałożone na stronę, które skupia uwagę na jednym zadaniu i blokuje wszystko inne, dopóki zadanie nie zostanie zakończone albo okno zamknięte.

Kod źródłowyBase UIRejestr
import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"

export default function DialogDemo() {
  return (
    <Dialog>
      <DialogTrigger render={<Button variant="outline" />}>
        Edytuj profil
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Edytuj profil</DialogTitle>
          <DialogDescription>
            Zmiany zobaczą wszyscy w twojej przestrzeni roboczej.
          </DialogDescription>
        </DialogHeader>
        <FieldGroup>
          <Field>
            <FieldLabel htmlFor="profile-name">Imię i nazwisko</FieldLabel>
            <Input id="profile-name" defaultValue="Ada Lovelace" />
          </Field>
          <Field>
            <FieldLabel htmlFor="profile-username">Nazwa użytkownika</FieldLabel>
            <Input id="profile-username" defaultValue="ada" />
          </Field>
        </FieldGroup>
        <DialogFooter>
          <DialogClose render={<Button variant="outline" />}>
            Anuluj
          </DialogClose>
          <Button>Zapisz zmiany</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

Instalacja

$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/dialog.json

Użycie

import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
<Dialog>
  <DialogTrigger render={<Button variant="outline" />}>Edit profile</DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Edit profile</DialogTitle>
      <DialogDescription>Changes are visible to everyone in your workspace.</DialogDescription>
    </DialogHeader>
    {/* … */}
    <DialogFooter>
      <DialogClose render={<Button variant="outline" />}>Cancel</DialogClose>
      <Button>Save changes</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

DialogContent sam renderuje portal, przyciemnione tło i okno. Wyzwalacze i przyciski zamykania przyjmują prop render, więc element, który otwiera okno, jest prawdziwym Button z prfct, a nie opakowaniem wokół niego.

Przykłady

Formularz

Najczęstsze okno dialogowe: krótki formularz, który edytuje jedną rzecz. Po otwarciu okna fokus trafia do pierwszego pola, a po zamknięciu wraca do wyzwalacza. Ogranicz się do kilku pól — wszystko dłuższe zasługuje na osobną stronę albo Sheet. Umieść pola i stopkę w jednym elemencie <form>, żeby Enter wysyłał formularz.

"use client"

import * as React from "react"
import { PlusIcon } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import {
  Field,
  FieldDescription,
  FieldGroup,
  FieldLabel,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput,
  InputGroupText,
} from "@/components/ui/input-group"
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select"

// Accents become plain letters (é → e, ł → l) instead of disappearing.
const slugify = (value: string) =>
  value
    .normalize("NFD")
    .replace(/\p{Diacritic}/gu, "")
    .replace(/ł/gi, "l")
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-|-$/g, "")

export default function DialogForm() {
  const [open, setOpen] = React.useState(false)
  const [name, setName] = React.useState("")

  return (
    <Dialog
      open={open}
      onOpenChange={(next) => {
        setOpen(next)
        if (!next) setName("")
      }}
    >
      <DialogTrigger render={<Button />}>
        <PlusIcon data-icon="inline-start" />
        Nowy projekt
      </DialogTrigger>
      <DialogContent>
        <form
          className="flex flex-col gap-5"
          onSubmit={(event) => {
            event.preventDefault()
            setOpen(false)
          }}
        >
          <DialogHeader>
            <DialogTitle>Utwórz projekt</DialogTitle>
            <DialogDescription>
              Projekt grupuje zgłoszenia, wdrożenia i dokumentację jednego produktu.
            </DialogDescription>
          </DialogHeader>
          <FieldGroup>
            <Field>
              <FieldLabel htmlFor="project-name">Nazwa</FieldLabel>
              <Input
                id="project-name"
                placeholder="Atlas"
                required
                value={name}
                onChange={(event) => setName(event.target.value)}
              />
            </Field>
            <Field>
              <FieldLabel htmlFor="project-url">Adres URL</FieldLabel>
              <InputGroup>
                <InputGroupAddon>
                  <InputGroupText>prfct.dev/</InputGroupText>
                </InputGroupAddon>
                <InputGroupInput
                  id="project-url"
                  readOnly
                  value={slugify(name) || "atlas"}
                  className="text-muted-foreground"
                />
              </InputGroup>
              <FieldDescription>
                Tworzony na podstawie nazwy. Możesz go później zmienić.
              </FieldDescription>
            </Field>
            <Field>
              <FieldLabel htmlFor="project-template">Szablon</FieldLabel>
              <NativeSelect
                id="project-template"
                defaultValue="web"
                className="w-full"
              >
                <NativeSelectOption value="blank">Pusty</NativeSelectOption>
                <NativeSelectOption value="web">
                  Aplikacja internetowa
                </NativeSelectOption>
                <NativeSelectOption value="docs">
                  Strona z dokumentacją
                </NativeSelectOption>
                <NativeSelectOption value="api">Usługa API</NativeSelectOption>
              </NativeSelect>
            </Field>
          </FieldGroup>
          <DialogFooter>
            <DialogClose render={<Button variant="outline" />}>
              Anuluj
            </DialogClose>
            <Button type="submit">Utwórz projekt</Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  )
}

Przewijana treść

Gdy treść jest wyższa niż obszar widoku, przewijaj tylko środkową część okna, żeby tytuł i akcje pozostały widoczne. Samo okno nigdy nie jest większe niż obszar widoku pomniejszony o margines 1 rem z każdej strony.

import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"

const sections = [
  {
    title: "1. Twoje konto",
    body: "Odpowiadasz za aktywność na swoim koncie i za bezpieczeństwo danych logowania. Jeśli zauważysz nieuprawniony dostęp, natychmiast nas o tym poinformuj.",
  },
  {
    title: "2. Dozwolone korzystanie",
    body: "Nie używaj usługi do łamania prawa, naruszania praw innych osób, rozpowszechniania złośliwego oprogramowania ani zakłócania jej prawidłowego działania.",
  },
  {
    title: "3. Twoje treści",
    body: "To, co tworzysz, należy do ciebie. Udzielasz nam ograniczonej licencji na przechowywanie i wyświetlanie tych treści wyłącznie w zakresie niezbędnym do świadczenia ci usługi.",
  },
  {
    title: "4. Płatności",
    body: "Płatne plany odnawiają się automatycznie z końcem każdego okresu rozliczeniowego. Możesz zrezygnować w dowolnym momencie — rezygnacja zacznie obowiązywać z końcem bieżącego okresu.",
  },
  {
    title: "5. Dostępność",
    body: "Dążymy do miesięcznej dostępności na poziomie 99,95% i publikujemy incydenty na naszej stronie statusu. Planowane prace serwisowe ogłaszamy z co najmniej 48-godzinnym wyprzedzeniem.",
  },
  {
    title: "6. Rozwiązanie umowy",
    body: "Możesz zamknąć konto w dowolnym momencie. Możemy zawiesić konta naruszające niniejsze warunki i podamy ci powód, chyba że zabrania nam tego prawo.",
  },
  {
    title: "7. Zmiany",
    body: "O istotnych zmianach powiadomimy cię co najmniej 30 dni przed ich wejściem w życie. Dalsze korzystanie z usługi po tym terminie oznacza akceptację nowych warunków.",
  },
]

export default function DialogScrollable() {
  return (
    <Dialog>
      <DialogTrigger render={<Button variant="outline" />}>
        Przejrzyj warunki
      </DialogTrigger>
      <DialogContent className="max-w-xl">
        <DialogHeader>
          <DialogTitle>Warunki korzystania z usługi</DialogTitle>
          <DialogDescription>Ostatnia aktualizacja: 1 września 2026 r.</DialogDescription>
        </DialogHeader>
        {/* Only the body scrolls; the title and actions stay in view. */}
        <div className="-mx-6 max-h-[min(22rem,50dvh)] scrollbar-thin overflow-y-auto border-y px-6 py-5">
          <div className="flex flex-col gap-5">
            {sections.map((section) => (
              <section key={section.title} className="flex flex-col gap-1.5">
                <h3 className="text-sm font-semibold text-foreground">
                  {section.title}
                </h3>
                <p className="text-sm leading-[1.375rem] text-muted-foreground">
                  {section.body}
                </p>
              </section>
            ))}
          </div>
        </div>
        <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
          <DialogClose render={<Button variant="outline" />}>
            Odrzuć
          </DialogClose>
          <DialogClose render={<Button />}>Zaakceptuj</DialogClose>
        </div>
      </DialogContent>
    </Dialog>
  )
}

Tryb kontrolowany

Okna otwierane z pozycji menu, skrótem klawiszowym albo po zakończeniu operacji asynchronicznej nie mają własnego wyzwalacza. Wyrenderuj okno poza menu i steruj nim za pomocą open i onOpenChange.

Planowanie Q3
"use client"

import * as React from "react"
import { MoreHorizontalIcon, PencilIcon, Trash2Icon } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Field, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"

export default function DialogControlled() {
  const [open, setOpen] = React.useState(false)
  const [name, setName] = React.useState("Planowanie Q3")
  const [draft, setDraft] = React.useState(name)

  function rename(event: React.FormEvent) {
    event.preventDefault()
    setName(draft.trim() || name)
    setOpen(false)
  }

  return (
    <div className="flex items-center gap-3 rounded-xl border bg-card py-2 pr-2 pl-4 shadow-raised">
      <span className="text-sm font-medium">{name}</span>
      <DropdownMenu>
        <DropdownMenuTrigger
          render={
            <Button
              variant="ghost"
              size="icon-sm"
              aria-label="Akcje dokumentu"
            />
          }
        >
          <MoreHorizontalIcon />
        </DropdownMenuTrigger>
        <DropdownMenuContent align="end" className="w-44">
          <DropdownMenuGroup>
            <DropdownMenuItem
              onClick={() => {
                setDraft(name)
                setOpen(true)
              }}
            >
              <PencilIcon />
              Zmień nazwę…
            </DropdownMenuItem>
          </DropdownMenuGroup>
          <DropdownMenuSeparator />
          <DropdownMenuGroup>
            <DropdownMenuItem variant="destructive">
              <Trash2Icon />
              Usuń
            </DropdownMenuItem>
          </DropdownMenuGroup>
        </DropdownMenuContent>
      </DropdownMenu>

      {/* Opened from a menu item, so it has no trigger of its own: control it. */}
      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="max-w-md">
          <form onSubmit={rename} className="flex flex-col gap-5">
            <DialogHeader>
              <DialogTitle>Zmień nazwę dokumentu</DialogTitle>
              <DialogDescription>
                Nowa nazwa będzie widoczna dla wszystkich, którzy mają dostęp.
              </DialogDescription>
            </DialogHeader>
            <Field>
              <FieldLabel htmlFor="document-name">Nazwa</FieldLabel>
              <Input
                id="document-name"
                value={draft}
                onChange={(event) => setDraft(event.target.value)}
              />
            </Field>
            <DialogFooter>
              <DialogClose render={<Button variant="outline" />}>
                Anuluj
              </DialogClose>
              <Button type="submit">Zmień nazwę</Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </div>
  )
}
const [open, setOpen] = React.useState(false)

<DropdownMenuItem onClick={() => setOpen(true)}>Rename…</DropdownMenuItem>

<Dialog open={open} onOpenChange={setOpen}>
  <DialogContent>{/* … */}</DialogContent>
</Dialog>

DialogFooter to pas z delikatnie zabarwionym tłem, przylegający do dolnej krawędzi. Akcje umieszczaj po prawej, dodatkowy kontekst po lewej, a gdy okno potrzebuje tylko drogi wyjścia, użyj showCloseButton.

"use client"

import * as React from "react"
import { CheckIcon, CopyIcon, LinkIcon } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Field, FieldLabel } from "@/components/ui/field"
import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupInput,
} from "@/components/ui/input-group"

const url = "https://prfct.dev/share/7f3a-q3-roadmap"

export default function DialogShare() {
  const [copied, setCopied] = React.useState(false)

  React.useEffect(() => {
    if (!copied) return
    const timer = setTimeout(() => setCopied(false), 1600)
    return () => clearTimeout(timer)
  }, [copied])

  async function copy() {
    try {
      await navigator.clipboard.writeText(url)
      setCopied(true)
    } catch {
      // The clipboard can be denied; the link stays in the field to select.
    }
  }

  return (
    <Dialog>
      <DialogTrigger render={<Button variant="outline" />}>
        <LinkIcon data-icon="inline-start" />
        Udostępnij
      </DialogTrigger>
      <DialogContent className="max-w-md">
        <DialogHeader>
          <DialogTitle>Udostępnij link</DialogTitle>
          <DialogDescription>
            Każdy, kto ma link, może wyświetlić tę roadmapę.
          </DialogDescription>
        </DialogHeader>
        <Field>
          <FieldLabel htmlFor="share-link" className="sr-only">
            Link
          </FieldLabel>
          <InputGroup>
            <InputGroupInput id="share-link" defaultValue={url} readOnly />
            <InputGroupAddon align="inline-end">
              <InputGroupButton
                size="icon-xs"
                aria-label={copied ? "Skopiowano" : "Kopiuj link"}
                onClick={copy}
              >
                {copied ? (
                  <CheckIcon className="text-success-11" />
                ) : (
                  <CopyIcon />
                )}
              </InputGroupButton>
            </InputGroupAddon>
          </InputGroup>
        </Field>
        <DialogFooter showCloseButton className="sm:justify-between">
          <span className="self-center text-xs text-muted-foreground">
            Link wygaśnie za 30 dni
          </span>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

Szerokość

Domyślna maksymalna szerokość to max-w-lg (32 rem) — w sam raz dla formularza. Dla treści pomocniczych, np. listy skrótów, poszerz okno klasą max-w-*, ale zachowaj boczny margines: okno ma zawsze najwyżej calc(100% - 2rem) szerokości.

import { KeyboardIcon } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Kbd, KbdGroup } from "@/components/ui/kbd"

const groups = [
  {
    title: "Nawigacja",
    shortcuts: [
      { label: "Otwórz paletę poleceń", keys: ["⌘", "K"] },
      { label: "Przejdź do skrzynki odbiorczej", keys: ["G", "I"] },
      { label: "Przejdź do projektów", keys: ["G", "P"] },
      { label: "Szukaj", keys: ["/"] },
    ],
  },
  {
    title: "Edycja",
    shortcuts: [
      { label: "Utwórz zgłoszenie", keys: ["C"] },
      { label: "Przypisz do mnie", keys: ["I"] },
      { label: "Zmień status", keys: ["S"] },
      { label: "Przełącz motyw", keys: ["D"] },
    ],
  },
]

export default function DialogWide() {
  return (
    <Dialog>
      <DialogTrigger render={<Button variant="ghost" />}>
        <KeyboardIcon data-icon="inline-start" />
        Skróty
      </DialogTrigger>
      <DialogContent className="max-w-2xl">
        <DialogHeader>
          <DialogTitle>Skróty klawiszowe</DialogTitle>
          <DialogDescription>
            Naciśnij <Kbd>?</Kbd> w dowolnym miejscu, aby otworzyć tę listę.
          </DialogDescription>
        </DialogHeader>
        <div className="grid gap-8 sm:grid-cols-2">
          {groups.map((group) => (
            <section key={group.title} className="flex flex-col gap-2">
              <h3 className="text-overline text-muted-foreground">
                {group.title}
              </h3>
              <ul className="flex flex-col">
                {group.shortcuts.map((shortcut) => (
                  <li
                    key={shortcut.label}
                    className="flex items-center justify-between gap-4 border-b py-2 text-sm last:border-0"
                  >
                    <span className="text-foreground">{shortcut.label}</span>
                    <KbdGroup>
                      {shortcut.keys.map((key) => (
                        <Kbd key={key}>{key}</Kbd>
                      ))}
                    </KbdGroup>
                  </li>
                ))}
              </ul>
            </section>
          ))}
        </div>
      </DialogContent>
    </Dialog>
  )
}

Wytyczne

Kiedy używać

  • Aby zebrać niewielką ilość danych bez opuszczania strony: zmiana nazwy, zaproszenie, edycja kilku pól.
  • Aby pokazać informację, którą trzeba potwierdzić, zanim przejdzie się dalej.
  • Aby potwierdzić zadanie rozpoczęte na bieżącej stronie, z kontekstem wystarczającym do podjęcia decyzji.

Kiedy nie używać

  • Do potwierdzania akcji nieodwracalnych lub niszczących dane — użyj Alert Dialog, którego nie da się zamknąć kliknięciem obok.
  • Do długich formularzy, procesów wieloetapowych i wszystkiego, co trzeba porównywać z zawartością strony — użyj Sheet albo osobnej strony.
  • Do komunikatu o powodzeniu akcji — użyj Toast. Przerywanie pracy tylko po to, żeby powiedzieć, że wszystko poszło dobrze, to podatek od każdego zadania.
  • Do kontrolek kontekstowych powiązanych z jednym elementem — użyj Popover.

Wybór nakładki

Każda nakładka to kompromis między skupieniem uwagi a zachowaniem kontekstu. Wybierz najlżejszą, która wystarczy do zadania.

KomponentBlokuje stronęZamyka się po kliknięciu obokZastosowanie
DialogTakTakZadanie wymagające skupienia: krótki formularz, decyzja z kontekstem.
Alert DialogTakNiePotwierdzanie akcji nieodwracalnych lub niszczących dane.
SheetTakTakDłuższe formularze, szczegóły i filtry, przy których strona pozostaje w polu widzenia.
DrawerTakTak, także gestem przesunięciaPanele dolne projektowane z myślą o urządzeniach mobilnych, z gestami i punktami przyciągania.
PopoverNieTakNiewielka interaktywna treść zakotwiczona przy wyzwalaczu.
Hover CardNiePo odsunięciu kursoraPodglądy linków dla widzących użytkowników myszy.
TooltipNiePo odsunięciu kursoraKrótka tekstowa etykieta ikony lub kontrolki.

Jak pisać

Tytuł okna powinien mówić, co ono robi, a nie zadawać pytanie, które potem powtarzasz: Edytuj profil, Zaproś do zespołu. Główny przycisk nazwij od rezultatu i powtórz kluczowy rzeczownik, jeśli to pomaga: Zapisz zmiany, Wyślij 3 zaproszenia. Opis jest opcjonalny, ale zwykle warto poświęcić mu jedno zdanie kontekstu.

Zaproś do zespołuDostaną e-mail z zaproszeniem do Acme.
DobrzeTytuł nazywa zadanie, a przyciski — rezultaty.
Czy na pewno?Potwierdź, aby kontynuować.
ŹleOgólnikowe tytuły i para OK/Anuluj zmuszają do ponownego czytania wszystkiego.

Jedno okno naraz

Nigdy nie otwieraj okna dialogowego na innym oknie dialogowym. Jeśli zadanie wymaga drugiego kroku, podmień zawartość pierwszego okna albo przenieś cały proces na osobną stronę.

Dostępność

Okno realizuje wzorzec WAI-ARIA dialog. Base UI renderuje je z role="dialog", nadaje mu nazwę z DialogTitle i opis z DialogDescription. Nie ustawia aria-modal: gdy okno modalne jest otwarte, wszystko poza nim dostaje zamiast tego aria-hidden.

KlawiszDziałanie
EnterSpacja
Na wyzwalaczu: otwiera okno i przenosi do niego fokus.
Tab
Przenosi fokus do następnego elementu, który może go przyjąć. Fokus nie wychodzi poza okno.
ShiftTab
Przenosi fokus do poprzedniego elementu, który może go przyjąć; na początku przeskakuje na koniec.
Esc
Zamyka okno i przywraca fokus do elementu, który je otworzył.
  • Zawsze dodawaj tytuł. DialogTitle nadaje oknu dostępną nazwę. Jeśli projekt nie przewiduje widocznego tytułu, zostaw go i dodaj className="sr-only".
  • Fokus. Po otwarciu fokus trafia do pierwszego elementu, który może go przyjąć — a przy otwarciu dotykiem do samego okna, żeby nie wysuwała się klawiatura ekranowa. Zmienisz to propsami initialFocus i finalFocus na DialogContent.
  • Reszta strony jest nieaktywna. Gdy okno modalne jest otwarte, przewijanie strony jest zablokowane, a treść poza oknem jest nieosiągalna dla myszy, klawiatury i czytnika ekranu.
  • Droga wyjścia. Zostaw przycisk zamykania (showCloseButton, domyślnie włączony) albo przycisk DialogClose w stopce. Osoby korzystające z czytnika ekranu na urządzeniu dotykowym nie mogą nacisnąć Esc.
  • Ruch. Okno pojawia się z przenikaniem i skalowaniem w ciągu 320 ms, z krzywą przejścia enter, a znika szybciej, niż się pojawiło. Przy ograniczonym ruchu pojawia się natychmiast.

Dokumentacja API

Dialog

Komponent główny. Nie renderuje żadnego elementu. Przyjmuje wszystkie propsy Dialog.Root z Base UI.

PropTypDomyślnie
open

Czy okno jest otwarte. Używaj razem z onOpenChange, żeby sterować oknem.

booleanBrak wartości domyślnej
defaultOpen

Czy okno jest początkowo otwarte, w trybie niekontrolowanym.

booleanfalse
onOpenChange

Wywoływana, gdy okno się otwiera lub zamyka. details.reason podaje przyczynę: trigger-press, outside-press, escape-key, close-press…

(open: boolean, details) => voidBrak wartości domyślnej
onOpenChangeComplete

Wywoływana po zakończeniu animacji wejścia lub wyjścia.

(open: boolean) => voidBrak wartości domyślnej
modal

true blokuje przewijanie i interakcję poza oknem. "trap-focus" tylko zatrzymuje fokus w oknie. false pozwala na interakcję ze stroną.

boolean | "trap-focus"true
disablePointerDismissal

Zapobiega zamknięciu po kliknięciu poza oknem.

booleanfalse
actionsRef

Imperatywny uchwyt do zamknięcia lub odmontowania okna.

RefObject<{ close, unmount }>Brak wartości domyślnej

DialogTrigger

Otwiera okno. Renderuje <button>; użyj render, żeby wyrenderować Button z prfct.

PropTypDomyślnie
render

Podmienia renderowany element, nie zmieniając działania.

ReactElement | (props, state) => ReactElementBrak wartości domyślnej
nativeButton

Ustaw false, gdy render zwraca element inny niż przycisk.

booleantrue

DialogContent

Renderuje portal, przyciemnione tło i samo okno. Dwa komponenty, z których korzysta — DialogPortal i DialogOverlay — też są eksportowane, na wypadek układów, w których rozmieszczasz je samodzielnie.

PropTypDomyślnie
showCloseButton

Renderuje w prawym górnym rogu przycisk z ikoną, który zamyka okno.

booleantrue
initialFocus

Element, który dostaje fokus po otwarciu okna. Domyślnie pierwszy element osiągalny klawiszem Tab.

boolean | RefObject | (interaction) => HTMLElement | booleanBrak wartości domyślnej
finalFocus

Element, który dostaje fokus po zamknięciu okna. Domyślnie wyzwalacz.

boolean | RefObject | (interaction) => HTMLElement | booleanBrak wartości domyślnej
className

Łączone z klasami okna. Szerokość nadpiszesz klasą max-w-*.

stringBrak wartości domyślnej

DialogHeader, DialogTitle, DialogDescription

DialogHeader układa tytuł i opis jeden pod drugim i rezerwuje miejsce na przycisk zamykania. DialogTitle renderuje <h2> i nadaje oknu nazwę; DialogDescription renderuje <p> i je opisuje.

DialogFooter

Pas z delikatnie zabarwionym tłem, przylegający do dolnej krawędzi okna. Na małych ekranach układa akcje jedna pod drugą, od sm wzwyż wyrównuje je do prawej.

PropTypDomyślnie
showCloseButton

Dodaje na końcu przycisk zamykania w wariancie outline.

booleanfalse

DialogClose

Zamyka okno. Renderuje <button>; użyj render, żeby wyrenderować Button z prfct.