Drawer
StabilnyPanel projektowany z myślą o dotyku, który wysuwa się od krawędzi, podąża za palcem, zatrzymuje się w punktach przyciągania i zamyka gestem przesunięcia.
Instalacja
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/drawer.jsonUżycie
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"<Drawer showSwipeHandle>
<DrawerTrigger render={<Button variant="outline" />}>Set daily goal</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Daily move goal</DrawerTitle>
<DrawerDescription>Set your daily activity goal.</DrawerDescription>
</DrawerHeader>
{/* … */}
<DrawerFooter>
<DrawerClose render={<Button size="lg" />}>Save goal</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>Szuflada opiera się na komponencie Drawer z Base UI: panel podąża za wskaźnikiem podczas przeciągania, zamyka się, gdy gest jest wystarczająco szybki lub długi, i osiada w najbliższym punkcie zatrzymania, zamiast stanąć tam, gdzie puścił go palec.
Przykłady
Panel dolny
Wariant domyślny: szuflada, która wysuwa się od dołu i zamyka przesunięciem w dół. showSwipeHandle renderuje uchwyt, który sygnalizuje, że panel można przeciągać. Wyśrodkuj treść w kontenerze z klasą max-w-*, żeby pozostała czytelna na tabletach — wzorcowym przykładem jest panel udostępniania.
Punkty przyciągania
snapPoints pozwala szufladzie zatrzymywać się na kilku wysokościach. Ułamki od 0 do 1 oznaczają część wysokości obszaru widoku, liczby większe od 1 — piksele, a ciągi znaków przyjmują px i rem. Szuflada otwiera się w pierwszym punkcie; przeciągnij ją w górę, żeby dotrzeć do następnego.
<Drawer showSwipeHandle snapPoints={[0.45, 1]}>Kierunki
swipeDirection określa jednocześnie krawędź i gest zamykania: down (domyślnie), up, left albo right. Szuflady boczne zajmują na telefonach 75% szerokości, a od sm wzwyż mają 24 rem.
Zagnieżdżanie
Gdy otworzysz szufladę z wnętrza innej, szuflada nadrzędna cofa się w głąb stosu — nieco mniejsza i przygaszona — żeby było widać, dokąd się wróci. Gdy zamkniesz gestem szufladę podrzędną, nadrzędna znów wysunie się na pierwszy plan.
Responsywność
Na komputerze do wyśrodkowanego okna Dialog łatwiej sięgnąć kursorem; na telefonie dolna szuflada jest w zasięgu kciuka. Zachowaj wspólną treść i przełączaj kontener za pomocą useIsMobile.
const isMobile = useIsMobile()
return isMobile ? (
<Drawer showSwipeHandle>{/* … */}</Drawer>
) : (
<Dialog>{/* … */}</Dialog>
)Wytyczne
Kiedy używać
- Do zadań kontekstowych na urządzeniach dotykowych: wyboru wartości, krótkich formularzy, udostępniania, filtrów.
- Gdy treść zyskuje na tym, że panel może zatrzymać się na kilku wysokościach — np. mapa z listą miejsc.
Kiedy nie używać
- W desktopowych układach obsługiwanych głównie myszą — użyj Dialog albo Sheet.
- Do potwierdzania akcji nieodwracalnych — użyj Alert Dialog, którego nie da się przypadkiem zamknąć gestem.
- Do długich, złożonych formularzy — daj im osobną stronę.
Gest to skrót, nigdy jedyna droga
Wszystko, co robi gest, musi być możliwe także stuknięciem lub klawiszem. Zostaw w stopce widoczną akcję zamknięcia lub anulowania i nie polegaj na przesuwaniu między punktami przyciągania, żeby odsłonić kluczową treść.
W zasięgu kciuka
Główne akcje umieszczaj na dole szuflady, na całą szerokość, w rozmiarze lg (40 px wysokości). Tam są kciuki, a taki przycisk z zapasem spełnia wymóg minimalnego celu dotyku 24 px.
Dostępność
Szuflada jest modalnym oknem dialogowym: zatrzymuje fokus w środku, blokuje przewijanie strony, a nazwę i opis otrzymuje z DrawerTitle i DrawerDescription.
| Klawisz | Działanie |
|---|---|
EnterSpacja | Na wyzwalaczu: otwiera szufladę i przenosi do niej fokus. |
Tab | Przechodzi między kontrolkami szuflady. Dopóki jest otwarta, fokus nie wychodzi poza nią. |
ShiftTab | Przenosi fokus wstecz. |
Esc | Zamyka szufladę i przywraca fokus do wyzwalacza. |
- Zawsze dodawaj tytuł. Nadaje szufladzie nazwę dla technologii wspomagających; jeśli projekt go nie przewiduje, ukryj go klasą
sr-only. - Uchwyt do przeciągania jest dekoracyjny i ukryty przed technologiami wspomagającymi — zapewnij prawdziwy przycisk zamykania.
- Ruch. Podczas przeciągania szuflada podąża za wskaźnikiem 1:1, a potem osiada w ciągu 450 ms. Przy ograniczonym ruchu animacja osiadania znika; przeciąganie nadal podąża za palcem, bo ten ruch wywołuje człowiek, a nie interfejs.
Dokumentacja API
Drawer
Komponent główny. Nie renderuje żadnego elementu. Przyjmuje wszystkie propsy Drawer.Root z Base UI.
DrawerContent
Renderuje portal, przyciemnione tło, viewport i panel. Przyjmuje wszystkie propsy Drawer.Popup z Base UI, w tym initialFocus i finalFocus.
DrawerHeader, DrawerFooter
DrawerHeader zawiera tytuł i opis — w szufladach wysuwanych w pionie są one poniżej md wyśrodkowane, a powyżej wyrównane do lewej. DrawerFooter układa akcje jedna pod drugą, na całą szerokość, na dole panelu.
DrawerTitle, DrawerDescription
DrawerTitle renderuje <h2> i nadaje szufladzie nazwę. DrawerDescription renderuje <p> i ją opisuje.
DrawerTrigger, DrawerClose
Otwierają i zamykają szufladę. Oba renderują <button>; użyj render, żeby wyrenderować Button z prfct.