Skip to content

Resizable

Split panels the user can drag to resize, horizontally or vertically.

Stablev0.4.2added in v0.1.0@garn/ui/resizable
On this page

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.

terminal
npx garn-ui add resizable
First time? Set up garn in your project
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

SelectorState
[data-panel-group-direction=vertical]direction-vertical
:focus-visiblehandle-focus

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

Do
  • Give the PanelGroup a height (panels fill it) and set defaultSize/minSize per panel.
  • Use withHandle so the divider is visible and grabbable.
  • Persist sizes with the library's autoSaveId / onLayout when the split should be remembered.
Don't
  • 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

ArrowLeftArrowRightResize a horizontal handle.
ArrowUpArrowDownResize a vertical handle.
EnterCollapse / expand a collapsible panel.
A1.3.1Info and RelationshipsA2.1.1Keyboard
  • 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.