Resizable
A component for building resizable panel groups with draggable handles.
Overview
The Resizable component provides a flexible system for creating resizable panel layouts. Built on react-resizable-panels, it supports horizontal and vertical orientations, customizable handles, and flexible sizing constraints.
Usage
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@tilt-legal/cubitt-components/primitives";<ResizablePanelGroup orientation="horizontal">
<ResizablePanel>One</ResizablePanel>
<ResizableHandle />
<ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>Examples
Vertical
Use orientation="vertical" to stack panels vertically.
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
return (
<ResizablePanelGroup
orientation="vertical"
className="min-h-[300px] max-w-md rounded-lg border"
>
<ResizablePanel defaultSize={25}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Header</span>
</div>
</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={75}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Content</span>
</div>
</ResizablePanel>
</ResizablePanelGroup>
);
}With Handle
Add withHandle to display a visible drag handle on the resize bar.
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
return (
<ResizablePanelGroup
orientation="horizontal"
className="min-h-[200px] max-w-md rounded-lg border"
>
<ResizablePanel defaultSize={50}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">One</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Two</span>
</div>
</ResizablePanel>
</ResizablePanelGroup>
);
}Custom Handle
Pass a custom React element to withHandle for full control over the handle appearance.
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
return (
<ResizablePanelGroup orientation="horizontal">
<ResizablePanel
defaultSize={30}
className="h-[200px] rounded-lg border bg-background"
>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Sidebar</span>
</div>
</ResizablePanel>
<ResizableHandle
withHandle={<span className="h-8 w-1 rounded-full bg-border" />}
className="!w-2 !bg-transparent"
/>
<ResizablePanel
defaultSize={70}
className="h-[200px] rounded-lg border bg-background"
>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Content</span>
</div>
</ResizablePanel>
</ResizablePanelGroup>
);
}Pixel-Based Sizing
Use numeric values for pixel-based constraints. The second panel automatically fills remaining space.
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
return (
<ResizablePanelGroup
orientation="horizontal"
className="min-h-[200px] rounded-lg border"
>
<ResizablePanel defaultSize={280} minSize={200} maxSize={400}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Fixed Sidebar (280px)</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Flexible Content</span>
</div>
</ResizablePanel>
</ResizablePanelGroup>
);
}API Reference
ResizablePanelGroup
Container component that manages the resizable panel layout.
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | The orientation of the panel layout. |
onLayoutChange | (layout: Layout) => void | — | Callback when panel sizes change. |
className | string | — | Additional CSS classes for the panel group. |
ResizablePanel
Individual panel within the group.
Size props accept flexible units:
- Numbers are pixels (e.g.,
defaultSize={420}= 420px) - Strings without units are percentages (e.g.,
defaultSize="50"= 50%) - Strings with units use that unit (e.g.,
"10rem","50vh")
| Prop | Type | Default | Description |
|---|---|---|---|
defaultSize | number | string | — | Initial size (pixels, percentage, or CSS unit). |
minSize | number | string | — | Minimum size constraint. |
maxSize | number | string | — | Maximum size constraint. |
collapsible | boolean | false | Whether the panel can be collapsed. |
collapsedSize | number | string | — | Size when collapsed. |
onResize | (size) => void | — | Callback when panel is resized. |
className | string | — | Additional CSS classes for the panel. |
ResizableHandle
Draggable handle between panels.
| Prop | Type | Default | Description |
|---|---|---|---|
withHandle | boolean | React.ReactNode | false | Show a visible grip handle. Pass true for default, or a custom element. |
disabled | boolean | false | Disable resizing via this handle. |
className | string | — | Additional CSS classes for the handle. |
Hooks
useResizablePanelRef
Get a ref to imperatively control a panel (collapse, expand, resize).
import { useResizablePanelRef } from "@tilt-legal/cubitt-components/primitives";
function Component() {
const panelRef = useResizablePanelRef();
return (
<ResizablePanelGroup orientation="horizontal">
<ResizablePanel panelRef={panelRef} collapsible>
Sidebar
</ResizablePanel>
<ResizableHandle />
<ResizablePanel>Content</ResizablePanel>
</ResizablePanelGroup>
);
}
// Imperative methods:
panelRef.current?.collapse(); // Collapse the panel
panelRef.current?.expand(); // Expand the panel
panelRef.current?.isCollapsed(); // Check if collapsed
panelRef.current?.getSize(); // { asPercentage: number, inPixels: number }useResizableGroupRef
Get a ref to imperatively control the entire group layout.
import { useResizableGroupRef } from "@tilt-legal/cubitt-components/primitives";
function Component() {
const groupRef = useResizableGroupRef();
const resetLayout = () => {
groupRef.current?.setLayout({ left: 30, right: 70 });
};
return (
<ResizablePanelGroup groupRef={groupRef} orientation="horizontal">
<ResizablePanel id="left">Left</ResizablePanel>
<ResizableHandle />
<ResizablePanel id="right">Right</ResizablePanel>
</ResizablePanelGroup>
);
}
// Imperative methods:
groupRef.current?.getLayout(); // { [panelId]: percentage }
groupRef.current?.setLayout({ ... }); // Set new layout by panel IDsuseResizableDefaultLayout
Persist and restore layouts to storage (localStorage, sessionStorage, or custom).
import { useResizableDefaultLayout } from "@tilt-legal/cubitt-components/primitives";
function Component() {
const { defaultLayout } = useResizableDefaultLayout({
panelIds: ["sidebar", "content"],
storage: localStorage,
});
return (
<ResizablePanelGroup defaultLayout={defaultLayout} orientation="horizontal">
<ResizablePanel id="sidebar" defaultSize={280}>
Sidebar
</ResizablePanel>
<ResizableHandle />
<ResizablePanel id="content">Content</ResizablePanel>
</ResizablePanelGroup>
);
}Types
import type {
ResizablePanelGroupHandle,
ResizablePanelHandle,
ResizableLayout,
ResizablePanelSize,
} from "@tilt-legal/cubitt-components/primitives";Credits
Built with react-resizable-panels.