Skip to content
Documentation navigation
Setup

Components

Resizable

A panel layout with an accessible draggable divider.

Basic example

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.

# install
pnpm add @constructive-io/ui
# app/globals.css
@import '@constructive-io/ui/globals.css';
# import
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.

npm source
tsx
'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.

Layout callbacks and persistence

Examples

Vertical panelsSet direction="vertical" to stack panels and rotate the handle treatment automatically.

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.

ResizablePanelGroup

Root layout that coordinates panel percentages and resize handles.

PropTypeDefaultDescription
direction *'horizontal' | 'vertical'Sets the panel axis and matching keyboard resize direction.
onLayout(layout: number[]) => voidReports the current panel sizes as percentages after layout changes.
autoSaveIdstringPersists and restores the layout under a stable identifier.
keyboardResizeBynumberSets the percentage moved by an arrow-key interaction.

Also accepts react-resizable-panels props.

ResizablePanel

One region in the group with percentage-based constraints and resize callbacks.

PropTypeDefaultDescription
defaultSizenumberInitial panel size as a percentage.
minSizenumberSmallest allowed panel size as a percentage.
maxSizenumberLargest allowed panel size as a percentage.
collapsiblebooleanAllows the panel to collapse beyond its minimum size.
collapsedSizenumberPanel percentage used in its collapsed state.
onResize(size: number, previousSize?: number) => voidRuns when this panel changes size.

Also accepts react-resizable-panels props.

ResizableHandle

Accessible divider that supports pointer and keyboard resizing.

PropTypeDefaultDescription
withHandlebooleanfalseShows the Constructive grip treatment in the center of the divider.
disabledbooleanPrevents the divider from resizing its adjacent panels.
onDragging(isDragging: boolean) => voidReports when pointer-driven resizing starts and stops.

Also accepts react-resizable-panels props.