Resizable
Split panels the user can drag to resize, horizontally or vertically.
@garn/ui/resizableOn this page
Default
Two horizontal panels with a grip handle.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add resizable- Registry
resizable- Deps
react-resizable-panelslucide-react- Registry deps
utils
Import
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@garn/ui/resizable";Anatomy
The parts this component is built from — compose them to assemble it.
ResizablePanelGroupRequired[data-slot="resizable-panel-group"]The container; direction sets horizontal vs vertical and flows into the handle styling.
ResizablePanelRequired[data-slot="resizable-panel"]One pane; size with defaultSize / minSize / maxSize (percentages).
ResizableHandle[data-slot="resizable-handle"]The draggable divider between panels; withHandle shows a grip affordance.
Props
The component's public props and their types.
No component-specific props — this is a thin wrapper over its native element.
Styling
Target these data-slots and states, and remap these tokens, to restyle without forking the component.
[data-slot="resizable-panel-group"]States
| Selector | State | Description |
|---|---|---|
[data-panel-group-direction=vertical] | direction-vertical | Vertical layout — the group stacks and the handle rotates. |
:focus-visible | handle-focus | The handle shows a focus ring and is keyboard-resizable. |
When to use
Let users rebalance space between adjacent regions — a sidebar/content split, an editor/preview, multi-pane layouts.
Reach for something else when
- An overlay panel (use sheet/drawer)
- collapsible content (use collapsible/accordion)
- a fixed layout that shouldn't be user-resized (use CSS grid/flex).
Overview
Resizable lets users rebalance space between adjacent regions — a sidebar/content split, an editor/preview, a multi-pane layout. ResizablePanelGroup sets the direction, each ResizablePanel takes defaultSize/minSize/maxSize (percentages), and ResizableHandle is the draggable divider (withHandle shows a grip). Use it where users genuinely benefit from controlling proportions; for fixed structure, a normal grid/flex layout is simpler.
Guidelines
Add resizing only where users will actually want it. Power layouts — code editor + preview, list + detail — benefit; most pages don't, and a draggable seam everywhere adds complexity for no gain. Set sensible defaults so it's usable before anyone drags.
Constrain panels with min/max sizes. Floors and ceilings stop a pane from collapsing to nothing or swallowing the layout; pick limits that keep every region functional. Persist the user's chosen split where it makes sense.
Make the handle reachable and operable. Show a grip affordance, give the separator an accessible name, and support keyboard resizing (arrow keys) — not just pointer drag. Keep the hit area comfortable on touch.
Best practices
- Give the PanelGroup a height (panels fill it) and set
defaultSize/minSizeper panel. - Use
withHandleso the divider is visible and grabbable. - Persist sizes with the library's
autoSaveId/ onLayout when the split should be remembered.
- Don't ship a resizable layout the keyboard can't operate — the handle is keyboard-resizable; keep it reachable.
- Don't use it for overlay or collapsible patterns.
- Don't nest deep panel trees that confuse the resize model.
Content guidelines
- Label each pane by its content, and give the drag handle an aria-label that says what it resizes.
Troubleshooting
Panels collapse to nothing or the group is invisible.
Cause. The PanelGroup has no height (panels size relative to it).
Fix. Give the ResizablePanelGroup an explicit height (and use percentage defaultSizes).
Accessibility
- Role
separator- Focus
- The handle shows a ring and accepts arrow-key resizing.
Keyboard
| ArrowLeftArrowRight | Resize a horizontal handle. |
| ArrowUpArrowDown | Resize a vertical handle. |
| Enter | Collapse / expand a collapsible panel. |
- The handle is a focusable separator with aria-valuenow/min/max — it's resizable by keyboard, not just drag.
- Use `withHandle` (or otherwise signal the divider) so the resize affordance is discoverable.