Split a view into panels that resize by drag or keyboard. Built on react-resizable-panels.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup,} from "@/components/ui/resizable"export function Example() { return ( <ResizablePanelGroup orientation="horizontal" className="min-h-[200px] w-full max-w-md rounded-md border border-border" > <ResizablePanel defaultSize="25%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> One </span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel defaultSize="75%"> <ResizablePanelGroup orientation="vertical"> <ResizablePanel defaultSize="25%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Two </span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel defaultSize="75%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Three </span> </div> </ResizablePanel> </ResizablePanelGroup> </ResizablePanel> </ResizablePanelGroup> )}Installation
npx @arctis-sh/@arctis-sh/ui@latest add resizableUsage
import { ResizableHandle, ResizablePanel, ResizablePanelGroup,} from "@/components/ui/resizable"<ResizablePanelGroup orientation="horizontal" className="min-h-[200px] max-w-md rounded-md border border-border"> <ResizablePanel defaultSize="25%">Sidebar</ResizablePanel> <ResizableHandle /> <ResizablePanel defaultSize="75%">Main</ResizablePanel></ResizablePanelGroup>Composition
ResizablePanelGroup ├── ResizablePanel ├── ResizableHandle └── ResizablePanel
Basic
Nest groups to combine directions. This example uses a horizontal split with a vertical split on the right.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup,} from "@/components/ui/resizable"export function Example() { return ( <ResizablePanelGroup orientation="horizontal" className="min-h-[200px] w-full max-w-md rounded-md border border-border" > <ResizablePanel defaultSize="25%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> One </span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel defaultSize="75%"> <ResizablePanelGroup orientation="vertical"> <ResizablePanel defaultSize="25%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Two </span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel defaultSize="75%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Three </span> </div> </ResizablePanel> </ResizablePanelGroup> </ResizablePanel> </ResizablePanelGroup> )}Vertical
Use orientation="vertical" for stacked panels. Give the group a height, such as min-h-[200px].
import { ResizableHandle, ResizablePanel, ResizablePanelGroup,} from "@/components/ui/resizable"export function Example() { return ( <ResizablePanelGroup orientation="vertical" className="min-h-[200px] w-full max-w-md rounded-md border border-border" > <ResizablePanel defaultSize="25%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Header </span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel defaultSize="75%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Content </span> </div> </ResizablePanel> </ResizablePanelGroup> )}Handle
Pass withHandle on ResizableHandle for a visible grip. The grip rotates automatically in vertical groups.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup,} from "@/components/ui/resizable"export function Example() { return ( <div className="grid w-full max-w-md gap-6"> <ResizablePanelGroup orientation="horizontal" className="min-h-[200px] rounded-md border border-border" > <ResizablePanel defaultSize="25%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Sidebar </span> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel defaultSize="75%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Content </span> </div> </ResizablePanel> </ResizablePanelGroup> <ResizablePanelGroup orientation="vertical" className="min-h-[200px] rounded-md border border-border" > <ResizablePanel defaultSize="35%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Header </span> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel defaultSize="65%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Content </span> </div> </ResizablePanel> </ResizablePanelGroup> </div> )}Constraints
Use minSize and maxSize to set resize limits. Percentage strings, including unitless strings like "50", are relative to the group; numbers are pixels.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup,} from "@/components/ui/resizable"export function Example() { return ( <ResizablePanelGroup orientation="horizontal" className="min-h-[200px] w-full max-w-md rounded-md border border-border" > <ResizablePanel defaultSize="30%" minSize="20%" maxSize="50%" > <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> 20%–50% </span> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel minSize="30%"> <div className="grid h-full place-items-center"> <span className="text-sm font-medium tracking-wide text-foreground"> Remaining </span> </div> </ResizablePanel> </ResizablePanelGroup> )}API Reference
ResizablePanelGroup
| Prop | Type | Default |
|---|---|---|
| orientation | "horizontal" | "vertical" | "horizontal" |
| resizeTargetMinimumSize | { coarse: number; fine: number } | { coarse: 8, fine: 4 } |
| className | string | — |
<ResizablePanelGroup orientation="horizontal"> <ResizablePanel defaultSize="50%">A</ResizablePanel> <ResizableHandle /> <ResizablePanel defaultSize="50%">B</ResizablePanel></ResizablePanelGroup>ResizablePanel
Size props accept "25%", unitless percentage strings, or pixel numbers.
| Prop | Type | Default |
|---|---|---|
| defaultSize | string | number | — |
| minSize | string | number | — |
| maxSize | string | number | — |
| collapsible | boolean | — |
| collapsedSize | string | number | 0% |
| disabled | boolean | — |
| className | string | — |
<ResizablePanel defaultSize="50%">A</ResizablePanel>ResizableHandle
| Prop | Type | Default |
|---|---|---|
| withHandle | boolean | — |
| disabled | boolean | — |
| disableDoubleClick | boolean | — |
| className | string | — |
See the react-resizable-panels docs for the full primitive API.
<ResizableHandle />