Resizable

Pro

Split a surface into panels the user can drag to resize. No Radix primitive ships this, so the handle is hand-rolled: it carries role=separator, is arrow-key operable, and reports through aria-valuenow.

Sidebar
Editor
Preview

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add resizable

Usage#

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Anatomy#

import {  ResizablePanelGroup,  ResizablePanel,  ResizableHandle,} from "@/components/ui/resizable"<ResizablePanelGroup>  <ResizablePanel>...</ResizablePanel>  <ResizableHandle />  <ResizablePanel>...</ResizablePanel></ResizablePanelGroup>

Horizontal#

The default direction lays panels side-by-side. Give each panel a defaultSize weight (conventionally summing to 100), then drag the divider to redistribute the space between the two panels it sits between.

Left
Right

Vertical#

Set direction="vertical" to stack panels and drag a horizontal divider. The handle, cursor, and keyboard axis all flip automatically.

Chart
Table

With handle#

Add withHandle to render a minimal, fully-rounded grip pill: a clear "drag me" affordance for wide gutters. Without it the divider is a hairline that highlights on hover and focus.

Grip
Hairline
divider

Custom handle#

Pass children to a ResizableHandle to swap the visual entirely (an icon nub, a brand chip, your own shape) while keeping all the drag, keyboard, and ARIA behavior. The two examples below show a dotted chip and a bold brand pill.

Dotted chip
Brand pill
Done

Min & max sizes#

Clamp how far a panel can be dragged with minSize and maxSize. A number (or "30%") is a proportional weight; a pixel string like "240px" is a hard bound pinned as a real CSS min/max-width, so it holds at any group size: drag it, then shrink your window and the sidebar below keeps its 240px–360px range instead of scaling away.

240px–360px
min 320px

Collapsible#

Mark a panel collapsible and it snaps shut once dragged past half its minSize, settling at collapsedSize (default 0): the pattern for a sidebar that tucks away. Drag back out to restore it.

Collapsible
Content

Nested dashboard#

Groups nest: put a vertical ResizablePanelGroup inside a panel of a horizontal one to build a real dashboard split. Each group resizes independently.

Navigation
Overview
Activity

API reference#

ResizablePanelGroup

The split container: compose panels and handles as direct children, alternating panel, handle, panel. Give it a height via className (panels fill the box). Forwards all native <div> props; every part accepts className, merged last.

PropTypeDefaultDescription
direction"horizontal" | "vertical""horizontal"Lay panels side by side or stacked. The handle, cursor and keyboard axis flip with it.
onLayout(sizes: number[]) => void-Called with the panel weights (in DOM order) whenever a drag or key press changes the layout.
Data attributeDescription
data-direction"horizontal" or "vertical", mirroring direction.

ResizablePanel

One region of the split, sized by flex-grow weight. Forwards all native <div> props.

PropTypeDefaultDescription
defaultSizenumber-Starting weight, conventionally a percentage with all panels summing to 100. Omit it on every panel for an equal split.
minSizenumber | string-Smallest drag size. A number (or "30%") is a proportional weight; a pixel string like "240px" is a hard bound pinned as real CSS, so it holds as the window resizes.
maxSizenumber | string-Largest drag size, as a weight or a pixel string like "480px".
collapsibleboolean-Snaps the panel shut once dragged past half its minSize; drag back out to restore it.
collapsedSizenumber | string0Size the panel settles at when collapsed, as a weight or a pixel string.
asChildboolean-Render as the child element (Radix Slot) instead of a <div>.
Data attributeDescription
data-min-sizeThe minSize value, read by the handle during a drag.
data-max-sizeThe maxSize value.
data-collapsiblePresent when collapsible.
data-collapsed-sizeThe collapsedSize value.

ResizableHandle

The draggable divider between the two panels beside it, with role="separator" and live aria-valuenow. Arrow keys nudge 16px (Shift 48px), Home and End jump to the previous panel's min and max. Forwards all native <div> props.

PropTypeDefaultDescription
withHandleboolean-Shows the minimal rounded grip pill; without it the divider is a hairline that highlights on hover and focus.
childrenReact.ReactNode-Custom handle content centered on the divider. Replaces the withHandle pill while keeping the drag, keyboard and ARIA behavior.
disabledboolean-Disables dragging and keyboard resizing, and takes the handle out of the tab order.
Data attributeDescription
data-dragging"true" while a pointer drag is in progress. Style custom children with group-data-[dragging=true]/handle:.
data-disabled"true" when disabled.

FAQ#

Give each ResizablePanel a `defaultSize` weight, conventionally summing to 100. Omit it on every panel for an equal split.