Resizable
Split panes for admin layouts, docs and editors. Hairline dividers with a wide grab area follow the pointer; collapsible panels snap shut past half their minimum. Dividers are APG window splitters: arrows step, Home/End jump to the limits, Enter or double-click collapses with a spring. Groups nest.
#general
No messages yet.
Drag a divider, or focus it and use the arrow keys. Enter or double-click collapses.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup,} from "@/components/ui/resizable";export function AdminLayout({ nav, log, children,}: { nav: React.ReactNode; log: React.ReactNode; children: React.ReactNode;}) { return ( <ResizablePanelGroup className="h-dvh" onLayout={(sizes) => { document.cookie = `layout=${JSON.stringify(sizes)}; path=/`; }} > <ResizablePanel defaultSize={22} minSize={15} maxSize={40} collapsible> {nav} </ResizablePanel> <ResizableHandle aria-label="Resize navigation" withHandle /> <ResizablePanel> <ResizablePanelGroup direction="vertical"> <ResizablePanel defaultSize={70}>{children}</ResizablePanel> <ResizableHandle aria-label="Resize log" /> <ResizablePanel minSize={15} collapsible> {log} </ResizablePanel> </ResizablePanelGroup> </ResizablePanel> </ResizablePanelGroup> );}<ResizablePanelGroup>
Split panes (admin layouts, docs, editors). Sizes are % of the group. Handles are APG window splitters: arrows step, Home/End jump to the limits, Enter collapses a collapsible neighbor. Drag follows the pointer; keys and toggles spring. Panels and handles find their order in the DOM, so wrappers and Server Component parents work. Until hydration the layout is plain CSS (defaultSize as a flex basis, the others share the rest), so SSR already shows it.
directiondefault"horizontal"Direction"horizontal": panels side by side. "vertical": stacked.
keyboardStepdefault5number% per arrow key press.
onLayout(sizes: number[]) => voidFinal sizes after each drag, key or toggle, e.g. to save them in a cookie for SSR.
| Prop | Type | Default |
|---|---|---|
direction"horizontal": panels side by side. "vertical": stacked. | Direction | "horizontal" |
keyboardStep% per arrow key press. | number | 5 |
onLayoutFinal sizes after each drag, key or toggle, e.g. to save them in a cookie for SSR. | (sizes: number[]) => void | — |
Also accepts every <div> prop.
<ResizablePanel>
collapsedSizedefault0numberShare in % when collapsed (default 0), e.g. an icon rail.
collapsibledefaultfalsebooleanDragging past half the minimum snaps it shut; Enter or double-click on the handle toggles.
defaultSizenumberStarting share of the group in %. Panels without one split what is left evenly.
maxSizedefault100numberLargest size in % of the group.
minSizedefault10numberSmallest share in % (default 10).
| Prop | Type | Default |
|---|---|---|
collapsedSizeShare in % when collapsed (default 0), e.g. an icon rail. | number | 0 |
collapsibleDragging past half the minimum snaps it shut; Enter or double-click on the handle toggles. | boolean | false |
defaultSizeStarting share of the group in %. Panels without one split what is left evenly. | number | — |
maxSizeLargest size in % of the group. | number | 100 |
minSizeSmallest share in % (default 10). | number | 10 |
Also accepts every <div> prop.
<ResizableHandle>
The divider between two panels. withHandle adds a visible grip.
withHandlebooleanVisible grip in the middle of the divider.
| Prop | Type | Default |
|---|---|---|
withHandleVisible grip in the middle of the divider. | boolean | — |
Also accepts every <div> prop.
- type Direction
- "horizontal" | "vertical"
* required. Every component also takes className.