Sidebar
StabilnyStała nawigacja aplikacji — zwija się do paska ikon, na telefonach wysuwa się spoza ekranu, a jej wygląd dopasujesz do motywu co do piksela.
Instalacja
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/sidebar.jsonUżycie
Pasek boczny należy do układu aplikacji, a nie do strony. Owiń układ w SidebarProvider, wyrenderuj Sidebar obok SidebarInset, który zawiera stronę, i umieść SidebarTrigger wszędzie tam, skąd ludzie mają móc zwinąć i rozwinąć pasek.
import { cookies } from "next/headers"
import { AppSidebar } from "@/components/app-sidebar"
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar"
export default async function AppLayout({ children }: { children: React.ReactNode }) {
// The provider saves its state in a cookie; read it to render the same state on the server.
const cookieStore = await cookies()
const defaultOpen = cookieStore.get("sidebar_state")?.value !== "false"
return (
<SidebarProvider defaultOpen={defaultOpen}>
<AppSidebar />
<SidebarInset>
<header className="flex h-12 items-center gap-2 border-b px-3">
<SidebarTrigger />
</header>
{children}
</SidebarInset>
</SidebarProvider>
)
}"use client"
import { HouseIcon, InboxIcon, SettingsIcon } from "lucide-react"
import Link from "next/link"
import { usePathname } from "next/navigation"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarRail,
} from "@/components/ui/sidebar"
const items = [
{ title: "Home", href: "/", icon: HouseIcon },
{ title: "Inbox", href: "/inbox", icon: InboxIcon },
{ title: "Settings", href: "/settings", icon: SettingsIcon },
]
export function AppSidebar() {
const pathname = usePathname()
return (
<Sidebar collapsible="icon">
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<nav aria-label="Main">
<SidebarMenu>
{items.map((item) => {
const active = pathname === item.href
return (
<SidebarMenuItem key={item.href}>
<SidebarMenuButton
isActive={active}
tooltip={item.title}
render={
<Link href={item.href} aria-current={active ? "page" : undefined} />
}
>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
)
})}
</SidebarMenu>
</nav>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarRail />
</Sidebar>
)
}Anatomia
SidebarProvider state, keyboard shortcut, width variables
├─ Sidebar the panel (desktop) or a sheet (mobile)
│ ├─ SidebarHeader workspace switcher, search
│ ├─ SidebarContent scrolls
│ │ └─ SidebarGroup
│ │ ├─ SidebarGroupLabel · SidebarGroupAction
│ │ └─ SidebarGroupContent
│ │ └─ SidebarMenu
│ │ └─ SidebarMenuItem
│ │ ├─ SidebarMenuButton · SidebarMenuAction · SidebarMenuBadge
│ │ └─ SidebarMenuSub → SidebarMenuSubItem → SidebarMenuSubButton
│ ├─ SidebarFooter account, help
│ └─ SidebarRail a clickable edge that toggles the sidebar
└─ SidebarInset the page, with SidebarTrigger in its headerPrzykłady
Poniższe podglądy to prawdziwe paski boczne zamknięte w ramce. Na desktopie pasek boczny ma position: fixed; podgląd nadaje swojemu kontenerowi transform: translateZ(0), przez co kontener staje się blokiem zawierającym dla paska, i renderuje SidebarInset jako <div>, bo strona dokumentacji ma już <main>. W twojej aplikacji nie potrzebujesz ani jednego, ani drugiego.
Powłoka aplikacji
collapsible="icon" z SidebarRail i SidebarTrigger. Kliknij wyzwalacz, kliknij szynę wzdłuż prawej krawędzi paska albo naciśnij ⌘ B, aby zwinąć go do paska ikon.
Zwinięty do ikon
Po zwinięciu etykiety są przycinane, a każdy przycisk pokazuje swój tooltip po najechaniu i przy fokusie. Jeśli korzystasz z tego trybu, daj każdemu elementowi najwyższego poziomu ikonę i podpowiedź.
Warianty
sidebar przylega do strony i oddziela się od niej obramowaniem. floating zamienia się w wyniesioną kartę odsuniętą od krawędzi. inset wtapia się w tło strony, a treść leży na wyniesionym panelu — to najspokojniejsza opcja dla gęstych aplikacji.
Zwijane sekcje
Połącz Collapsible z menu, aby zbudować rozwijane sekcje. Collapsible renderuje SidebarMenuItem, a jego wyzwalacz — SidebarMenuButton, więc nie ma żadnych dodatkowych elementów opakowujących.
<Collapsible defaultOpen render={<SidebarMenuItem />} className="group/collapsible">
<CollapsibleTrigger render={<SidebarMenuButton />}>
<BookOpenIcon />
<span>Get started</span>
<ChevronRightIcon className="ml-auto transition-transform group-data-open/collapsible:rotate-90" />
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>…</SidebarMenuSub>
</CollapsibleContent>
</Collapsible>Akcje i odznaki
SidebarMenuBadge pokazuje licznik na końcu elementu. SidebarMenuAction dodaje akcję pomocniczą — często menu — która z showOnHover pojawia się dopiero po najechaniu. SidebarGroupAction dodaje akcję do etykiety grupy, na przykład Dodaj projekt.
Ładowanie
Renderuj SidebarMenuSkeleton, dopóki elementy się ładują. Szerokości różnią się w każdym wierszu, ale wynikają z useId, więc serwer i klient renderują ten sam HTML.
Tryby zwijania
Na ekranach węższych niż 768 px każdy pasek boczny staje się panelem Sheet, który wysuwa się od strony wskazanej w side; otwiera go SidebarTrigger.
Stan kontrolowany
Steruj propem open, aby zsynchronizować pasek boczny z własnym stanem, a wszystko, czego potrzebujesz, odczytasz z useSidebar() w dowolnym miejscu wewnątrz providera.
const [open, setOpen] = React.useState(true)
<SidebarProvider open={open} onOpenChange={setOpen}>…</SidebarProvider>const { state, open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar } = useSidebar()Szerokość i strona
Szerokości to zmienne CSS ustawione na providerze — --sidebar-width (16 rem) i --sidebar-width-icon (3 rem). Przekaż side="right", aby umieścić pasek przy przeciwnej krawędzi, na przykład jako panel inspektora.
<SidebarProvider
style={{ "--sidebar-width": "18rem", "--sidebar-width-icon": "3.5rem" } as React.CSSProperties}
>
<Sidebar side="right" variant="floating">…</Sidebar>
</SidebarProvider>Dostosowywanie motywu
Pasek boczny ma własne tokeny semantyczne, więc może różnić się od strony bez zmian w komponentach.
Wytyczne
Kiedy używać
- W aplikacjach, które mają więcej niż pięć głównych miejsc docelowych albo miejsca, między którymi ludzie przechodzą przez cały dzień.
- Gdy nawigacja obejmuje zagnieżdżone sekcje, projekty lub zapisane widoki, które muszą być w zasięgu jednego kliknięcia.
Kiedy nie używać
- Przy kilku miejscach docelowych — nagłówek z Tabs albo Navigation Menu zajmie mniej miejsca.
- Na stronach marketingowych i w dokumentacji, gdzie treść zasługuje na całą szerokość.
- Jako miejsce na ustawienia lub formularze — użyj komponentu Sheet albo osobnej strony.
Porządkuj według tego, co ludzie robią
Grupuj elementy według zadań, nadaj każdej grupie etykietę i ogranicz etykiety do jednego lub dwóch słów. Przełącznik przestrzeni roboczej lub konta umieść w nagłówku, a pomoc, ustawienia i profil — w stopce, żeby środek zawierał wyłącznie miejsca docelowe.
Pokazuj bieżące położenie
Oznacz jako bieżący dokładnie jeden element za pomocą isActive — i ustaw aria-current="page" na jego linku, żeby technologie wspomagające również to przekazały. W zagnieżdżonych sekcjach rozwiń tę, która zawiera bieżącą stronę.
Przewidywalne zwijanie
Wybierz jeden tryb zwijania dla całej aplikacji i zapamiętuj wybór ludzi (provider zapisuje ciasteczko sidebar_state; odczytaj je w układzie aplikacji). Nie zwijaj paska bocznego automatycznie przy przechodzeniu między stronami.
Dostępność
| Klawisz | Działanie |
|---|---|
Tab | Przechodzi kolejno przez przyciski i linki paska bocznego. |
EnterSpacja | Aktywuje element z fokusem albo rozwija lub zwija sekcję. |
⌘BCtrlB | Zwija lub rozwija pasek boczny z dowolnego miejsca w aplikacji — chyba że piszesz w polu tekstowym lub edytorze tekstu sformatowanego. |
Esc | Na urządzeniach mobilnych zamyka panel z paskiem bocznym i przywraca fokus na wyzwalacz. |
- Punkty orientacyjne. Owiń menu w
<nav aria-label="…">;SidebarInsetrenderuje<main>strony. - Bieżąca strona.
isActivejedynie stylizuje element. Dodajaria-current="page"do aktywnego linku. - Pasek ikon. Zwinięte elementy zachowują tekst w DOM, więc czytniki ekranu nadal odczytują etykietę; podpowiedzi pokazują tę samą nazwę osobom widzącym.
- Kontrolki zwijania.
SidebarTriggerma etykietę „Pokaż lub ukryj pasek boczny” — w języku ustawionym przez LocaleProvider.SidebarRailto ułatwienie dla myszy i jest wyłączony z kolejności tabulacji — użytkownicy klawiatury mają do dyspozycji wyzwalacz i skrót. - Urządzenia mobilne. Panel jest modalnym oknem dialogowym: fokus przechodzi do jego wnętrza, nie może go opuścić, dopóki panel jest otwarty, i wraca na wyzwalacz po zamknięciu.
Dokumentacja API
SidebarProvider
Przechowuje stan otwarcia, zapisuje go w ciasteczku i rejestruje skrót klawiszowy. Renderuje <div>, który układa pasek boczny i obszar strony obok siebie.
Sidebar
Panel nawigacji. Na urządzeniach mobilnych renderuje się wewnątrz komponentu Sheet.
SidebarMenuButton
Główna kontrolka elementu menu. Renderuje <button>; do nawigacji przekaż render={<Link />}.
SidebarMenuAction
Akcja pomocnicza na końcu elementu menu.
SidebarMenuSubButton
Link w podmenu. Domyślnie renderuje <a>.
SidebarInset
Obszar strony obok paska bocznego. Renderuje <main>; jeśli strona ma już taki element, przekaż render, aby użyć innego.
SidebarMenuSkeleton
Zastępczy wiersz na czas ładowania. showIcon dodaje przed tekstem blok wielkości ikony.
Pozostałe części
SidebarHeader, SidebarFooter, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarMenu, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuBadge i SidebarSeparator to ostylowane elementy układu, które przyjmują propsy swojego elementu HTML. SidebarGroupLabel i SidebarGroupAction przyjmują render. SidebarInput to kompaktowy Input. SidebarTrigger to ikonowy Button w wariancie ghost; SidebarRail to krawędź reagująca na najechanie, która zwija i rozwija pasek boczny.
useSidebar
Zwraca stan paska bocznego. Poza SidebarProvider rzuca błąd.