Przejdź do treści

Sheet

Stabilny

Panel wysuwany z krawędzi ekranu na dłuższe formularze, szczegóły i filtry — strona pod spodem pozostaje przy tym w zasięgu wzroku.

Instalacja

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

Użycie

import {
  Sheet,
  SheetBody,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"
<Sheet>
  <SheetTrigger render={<Button variant="outline" />}>Edit issue</SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>Edit issue</SheetTitle>
      <SheetDescription>DAT-248 · Opened by Ada Lovelace</SheetDescription>
    </SheetHeader>
    <SheetBody>{/* scrollable content */}</SheetBody>
    <SheetFooter>
      <SheetClose render={<Button variant="outline" />}>Cancel</SheetClose>
      <Button>Save issue</Button>
    </SheetFooter>
  </SheetContent>
</Sheet>

Panel to Dialog osadzony przy krawędzi ekranu. Działa tak samo — pułapka fokusu, blokada przewijania, zamykanie klawiszem Esc — i dodaje trzyczęściowy układ: nieruchomy SheetHeader, przewijany SheetBodySheetFooter przypięty do dołu.

Przykłady

Krawędzie

side wybiera krawędź: right (domyślnie) do szczegółów i edycji, left do nawigacji, topbottom do krótkiej treści na całą szerokość. Panele wysuwane z boku mają 26 rem szerokości i nigdy nie podchodzą bliżej niż na 3 rem do przeciwległej krawędzi; panele górne i dolne zajmują najwyżej 85% wysokości okna.

Pływający

variant="floating" odsuwa panel o 8 px od krawędzi okna i zaokrągla wszystkie jego narożniki, więc wygląda jak powierzchnia unosząca się nad stroną, a nie jak część ramy okna. Pasuje do lekkich paneli, takich jak powiadomienia.

Filtry

Filtry to modelowe zastosowanie panelu: wiele kontrolek działających na listę, która pozostaje widoczna za przyciemnionym tłem. Umieść liczbę wyników w głównej akcji, żeby ludzie wiedzieli, co dostaną, zanim zatwierdzą wybór.

Na małych ekranach nawigacja aplikacji przenosi się do lewego panelu otwieranego przyciskiem menu. Bieżącą stronę oznacz atrybutem aria-current="page".

Szerokość

Szerokość to zwykła klasa narzędziowa, więc nadpisz ją przez className — na przykład className="w-[min(40rem,calc(100%-3rem))]" dla szerokiego widoku szczegółów.

Wytyczne

Kiedy używać

  • Do edycji lub podglądu elementu listy bez utraty miejsca na tej liście.
  • Do formularzy zbyt długich na okno dialogowe, które jednak nie zasługują na osobną stronę.
  • Do nawigacji pomocniczej i filtrów na małych ekranach.

Kiedy nie używać

  • Do szybkiej decyzji lub krótkiego formularza — użyj komponentu Dialog.
  • Do mobilnych paneli dolnych z gestami przesuwania i punktami przyciągania — użyj komponentu Drawer.
  • Do stałej nawigacji bocznej na dużych ekranach — użyj komponentu Sidebar.

Struktura

Nagłówek i stopka powinny być krótkie, żeby miejsce zostało dla treści. Tytuł nazywa obiekt, opis dodaje jedną linijkę kontekstu (identyfikator, właściciela, liczbę), a stopka mieści najwyżej dwie akcje i opcjonalne Resetuj po przeciwnej stronie.

Dobrze.Akcje są w przypiętej stopce, zawsze w zasięgu ręki.
Źle.Akcje na końcu długiej treści znikają z widoku, gdy ją przewijasz.

Nie nakładaj paneli na siebie

Okno dialogowe otwarte nad panelem jest w porządku, gdy służy do potwierdzenia. Panel otwarty nad panelem — już nie: podmień treść albo przenieś ją na osobną stronę.

Dostępność

Panel jest modalnym oknem dialogowym z role="dialog"; nazwę nadaje mu SheetTitle, a opis — SheetDescription.

KlawiszDziałanie
EnterSpacja
Na wyzwalaczu: otwiera panel i przenosi do niego fokus.
Tab
Przechodzi między kontrolkami panelu. Fokus nie opuszcza panelu, dopóki ten się nie zamknie.
ShiftTab
Przenosi fokus wstecz, a z początku przeskakuje na koniec.
Esc
Zamyka panel i przywraca fokus na wyzwalacz.
  • Zawsze dodawaj tytuł. Użyj className="sr-only" na SheetTitle, gdy projekt pokazuje w tym miejscu coś innego, na przykład logo.
  • Przycisk zamykania (showCloseButton, domyślnie włączony) to sposób, w jaki użytkownicy czytników ekranu na urządzeniach dotykowych opuszczają panel. Zostaw go albo umieść SheetClose w stopce.
  • Kolejność czytania. Nagłówek, treść i stopka występują w kolejności DOM, więc czytniki ekranu i użytkownicy klawiatury docierają do akcji w stopce po treści — w tej samej kolejności, w jakiej widzą je wszyscy.
  • Ruch. Panele wsuwają się w ciągu 320 ms z krzywą przejścia enter i znikają w 160 ms. Przy ograniczonym ruchu pojawiają się od razu na swoim miejscu.

Dokumentacja API

Sheet

Komponent główny. Nie renderuje żadnego elementu. Przyjmuje wszystkie propsy Dialog.Root z Base UI: open, defaultOpen, onOpenChange, modal, disablePointerDismissal, actionsRef.

SheetContent

Renderuje portal, przyciemnione tło i sam panel.

PropTypDomyślnie
side

Krawędź, z której wysuwa się panel.

"top" | "right" | "bottom" | "left""right"
variant

floating odsuwa panel o 8 px od krawędzi okna i zaokrągla wszystkie narożniki.

"default" | "floating""default"
showCloseButton

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

booleantrue
initialFocus

Element, który otrzymuje fokus po otwarciu.

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

Element, który otrzymuje fokus po zamknięciu.

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

Łączona z klasami panelu. Szerokość paneli z lewej i prawej strony nadpiszesz klasami w-*.

stringBrak wartości domyślnej

SheetHeader, SheetBody, SheetFooter

SheetHeader zawiera tytuł i opis oraz zostawia miejsce na przycisk zamykania. SheetBody rośnie, by wypełnić panel, i przewija się niezależnie. SheetFooter jest przypięty do dołu i oddzielony cienką linią; na małych ekranach układa przyciski jeden pod drugim, a od sm wzwyż wyrównuje je do prawej.

SheetTitle, SheetDescription

SheetTitle renderuje <h2> i nadaje panelowi nazwę. SheetDescription renderuje <p> i go opisuje.

SheetTrigger, SheetClose

Otwierają i zamykają panel. Oba renderują <button>; użyj render, aby wyrenderować Button z prfct.