Components
Resizable
A panel layout with an accessible draggable divider.
Installation
Choose the package when you want centralized updates, or copy the source through the registry when you want local ownership.
Install the package, import its global tokens once, then use this exact subpath.
pnpm add @constructive-io/ui@import '@constructive-io/ui/globals.css';import { ResizablePanelGroup } from '@constructive-io/ui/resizable';When to use
- Use Resizable when adjacent work areas need user-adjustable space, such as an editor beside a preview or a sidebar beside a data grid.
- Use a fixed responsive layout when resizing would not improve the task. Use a collapsible disclosure when a secondary panel only needs to be shown or hidden.
Basic usage
Place ResizablePanel and ResizableHandle as alternating children of ResizablePanelGroup, set the group direction, and give each panel practical size constraints.
'use client';
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@constructive-io/ui/resizable';
const TABLES = ['users', 'organizations', 'databases', 'api_keys', 'sessions'];
export function BasicResizableDemo() {
return (<div className="h-64 w-full max-w-4xl overflow-hidden rounded-lg border bg-background">
<ResizablePanelGroup direction="horizontal">
<ResizablePanel defaultSize={32} minSize={20}>
<div className="h-full p-4">
<p className="text-pretty mb-2 text-xs font-medium uppercase tracking-wide text-muted-foreground">Tables</p>
<ul className="flex flex-col gap-1 text-sm">
{TABLES.map((t) => (<li key={t} className="rounded px-2 py-1 hover:bg-muted/50">
{t}
</li>))}
</ul>
</div>
</ResizablePanel>
<ResizableHandle withHandle aria-label="Resize table browser panels"/>
<ResizablePanel defaultSize={68}>
<div className="flex h-full flex-col p-4">
<p className="text-pretty text-sm font-medium">users</p>
<p className="text-pretty mt-1 text-sm text-muted-foreground">
8 columns · 1,250 rows. Drag the divider to resize the panels.
</p>
</div>
</ResizablePanel>
</ResizablePanelGroup>
</div>);
}
Layout callbacks and persistence
The panel group owns its live layout: defaultSize initializes panels and onLayout reports each committed percentage. Use autoSaveId for persistence, or an imperative group or panel ref when the application must set a layout directly.
Examples
Accessibility
- Keep one ResizableHandle between every pair of ResizablePanel elements. The underlying library gives each handle separator semantics and keyboard resizing behavior.
- Give each handle an aria-label when the adjacent panel names do not make its purpose obvious. A visible grip is decorative and does not replace that name.
- Choose minSize and maxSize values that keep both panels usable at every supported viewport, and verify resizing with arrow keys as well as a pointer.
API Reference
Constructive-specific behavior is listed here. Each part links to its inherited platform or primitive contract.
ResizablePanelGroupRoot layout that coordinates panel percentages and resize handles.
| Prop | Type | Default | Description |
|---|---|---|---|
| direction * | 'horizontal' | 'vertical' | — | Sets the panel axis and matching keyboard resize direction. |
| onLayout | (layout: number[]) => void | — | Reports the current panel sizes as percentages after layout changes. |
| autoSaveId | string | — | Persists and restores the layout under a stable identifier. |
| keyboardResizeBy | number | — | Sets the percentage moved by an arrow-key interaction. |
Also accepts react-resizable-panels props.
ResizablePanelOne region in the group with percentage-based constraints and resize callbacks.
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultSize | number | — | Initial panel size as a percentage. |
| minSize | number | — | Smallest allowed panel size as a percentage. |
| maxSize | number | — | Largest allowed panel size as a percentage. |
| collapsible | boolean | — | Allows the panel to collapse beyond its minimum size. |
| collapsedSize | number | — | Panel percentage used in its collapsed state. |
| onResize | (size: number, previousSize?: number) => void | — | Runs when this panel changes size. |
Also accepts react-resizable-panels props.
ResizableHandleAccessible divider that supports pointer and keyboard resizing.
| Prop | Type | Default | Description |
|---|---|---|---|
| withHandle | boolean | false | Shows the Constructive grip treatment in the center of the divider. |
| disabled | boolean | — | Prevents the divider from resizing its adjacent panels. |
| onDragging | (isDragging: boolean) => void | — | Reports when pointer-driven resizing starts and stops. |
Also accepts react-resizable-panels props.