Resizable
resizableBuilds keyboard-accessible horizontal or vertical split panes with size constraints.
Usage
Horizontal two columns
direction=horizontal, drag the vertical handle to increase or decrease, and min constrains the minimum width.
- src/
- app/
- page.tsx
- layout.tsx
- components/
- nav.tsx
- card.tsx
- lib/
- utils.ts
- package.json
- tsconfig.json
1export function Card({ title, children }) {2 return (3 <section className="rounded-lg border p-4">4 <h3 className="font-semibold">{title}</h3>5 <div className="mt-2 text-sm">{children}</div>6 </section>7 );8}
<ResizablePanelGroup direction="horizontal" defaultSizes={[35, 65]}>
<ResizablePanel min={20}><FileTree /></ResizablePanel>
<ResizableHandle />
<ResizablePanel><Editor /></ResizablePanel>
</ResizablePanelGroup>Vertical up and down columns
direction=vertical, the handle becomes horizontal, drag the upper and lower panels to increase the height.
- Customer · Ms. Wang: Has it been shipped?
- Customer Service · Xiaolian: It has been arranged to be sent out today 📦
- Customer · Ms. Wang: OK, thank you!
<ResizablePanelGroup direction="vertical" defaultSizes={[55, 45]}>
<ResizablePanel min={20}><ChatLog /></ResizablePanel>
<ResizableHandle />
<ResizablePanel min={20}><LogPanel /></ResizablePanel>
</ResizablePanelGroup>Three-column editor layout
Multi-panel + multi-handle; defaultSizes gives the initial scale, and the keyboard ←/→ can also be fine-tuned.
- src/
- app/
- page.tsx
- layout.tsx
- components/
- nav.tsx
- card.tsx
- lib/
- utils.ts
- package.json
- tsconfig.json
1export function Card({ title, children }) {2 return (3 <section className="rounded-lg border p-4">4 <h3 className="font-semibold">{title}</h3>5 <div className="mt-2 text-sm">{children}</div>6 </section>7 );8}
Monthly Overview
There were 1,284 new orders this month, a month-on-month increase of 12%.
<ResizablePanelGroup direction="horizontal" defaultSizes={[24, 46, 30]}>
<ResizablePanel min={15}><FileTree /></ResizablePanel>
<ResizableHandle />
<ResizablePanel min={25}><Editor /></ResizablePanel>
<ResizableHandle />
<ResizablePanel min={18}><Preview /></ResizablePanel>
</ResizablePanelGroup>When to use
Use Resizable when users need to drag a handle to resize adjacent panels, such as an IDE with three columns or a chat list beside its detail view. Use Viewport when layout should rearrange automatically from container width, or Layout for a fixed page skeleton.
Import
import { ResizablePanelGroup, ResizablePanel, ResizableHandle, applyResize, splitEqually } from "@hulianui/ui"Props
ResizablePanelGroup
| Name | Type | Default | Description |
|---|---|---|---|
| direction | "horizontal" | "vertical" | "horizontal" | horizontal places panels side by side with vertical separators; vertical stacks panels with horizontal separators. |
| sizes | number[] | — | Controlled percentage sizes, one per panel. Pair with onSizesChange. |
| defaultSizes | number[] | Equal shares | Initial uncontrolled sizes; defaults to an even split across panels. |
Inherited from HTMLAttributes<HTMLDivElement> (except onChange).
ResizablePanel
| Name | Type | Default | Description |
|---|---|---|---|
| min | number | 10 | Minimum size as a percentage. |
| max | number | 100 | Maximum size as a percentage. |
Inherited from HTMLAttributes<HTMLDivElement>.
ResizableHandle
| Name | Type | Default | Description |
|---|---|---|---|
| keyboardStep | number | 5 | Percentage adjusted per arrow-key press on the focusable role="separator". |
Inherited from HTMLAttributes<HTMLDivElement> (except aria-orientation).
Helper functions
splitEqually(n)— returns an array of equal percentage sizes fornpanels.applyResize(...)— calculates a new size array from a drag delta, including min/max clamping.
Events
ResizablePanelGroup
| Event | Type | Description |
|---|---|---|
| onSizesChange | (sizes: number[]) => void | Size change callback. |
Slots
ResizablePanelGroup
| Slot | Type | Description |
|---|---|---|
| children* | ReactNode | Panels and Handles are arranged alternately. |
Example
// Three horizontal panels: file tree, editor, and preview
<ResizablePanelGroup direction="horizontal" defaultSizes={[24, 46, 30]}>
<ResizablePanel min={15}><FileTree /></ResizablePanel>
<ResizableHandle />
<ResizablePanel min={25}><Editor /></ResizablePanel>
<ResizableHandle />
<ResizablePanel min={18}><Preview /></ResizablePanel>
</ResizablePanelGroup>// Two vertical panels
<ResizablePanelGroup direction="vertical" defaultSizes={[55, 45]}>
<ResizablePanel min={20}><ChatLog /></ResizablePanel>
<ResizableHandle />
<ResizablePanel min={20}><LogPanel /></ResizablePanel>
</ResizablePanelGroup>Usage guidelines
- Alternate Panel and Handle children. Place exactly one
ResizableHandlebetween adjacentResizablePanelelements. Missing or extra handles make neighbor-based size redistribution target the wrong elements. - The size-array length must equal the panel count.
sizesanddefaultSizescontain one percentage per panel. UsesplitEqually(n)for initialization andapplyResizewhen calculating controlled updates manually. - In controlled mode, write the new
sizesback fromonSizesChange; otherwise dragging cannot update the layout.
Related
Layout · AdminLayout · ScrollArea · Viewport · AspectRatio · FitScreen
Playground
- src/
- app/
- page.tsx
- layout.tsx
- components/
- nav.tsx
- card.tsx
- lib/
- utils.ts
- package.json
- tsconfig.json
1export function Card({ title, children }) {2 return (3 <section className="rounded-lg border p-4">4 <h3 className="font-semibold">{title}</h3>5 <div className="mt-2 text-sm">{children}</div>6 </section>7 );8}
<ResizablePanelGroup direction="horizontal" defaultSizes={[40, 60]}>
<ResizablePanel min={20}><FileTree /></ResizablePanel>
<ResizableHandle />
<ResizablePanel><Editor /></ResizablePanel>
</ResizablePanelGroup>