@biem/ui

Resizable

A group of panels that users resize by dragging the handle between them.

A resizable panel group divides an area into panels and places a handle between them. Users drag a handle to give one panel more room and its neighbor less, or they focus the handle and press the arrow keys. A double-click on a handle returns a panel that has a default size to that size. The group fills the width and the height of the element around it, so that element sets the size of the whole area.

Orders
Order details

Usage

resizable-default.tsx
import {
	ResizableHandle,
	ResizablePanel,
	ResizablePanelGroup,
} from "@biem/ui/components/ui/resizable";

export function ResizableDefault() {
	return (
		<div className="h-40 w-full max-w-sm rounded-lg border">
			<ResizablePanelGroup>
				<ResizablePanel>
					<div className="flex h-full items-center justify-center overflow-hidden text-sm">
						Orders
					</div>
				</ResizablePanel>
				<ResizableHandle/>
				<ResizablePanel>
					<div className="flex h-full items-center justify-center overflow-hidden text-sm">
						Order details
					</div>
				</ResizablePanel>
			</ResizablePanelGroup>
		</div>
	);
}

Examples

Horizontal

Side-by-side panels suit layouts in which content benefits from width, such as a navigation next to the content it opens. The group uses this arrangement by default, and orientation set to "horizontal" states it explicitly.

Orders
Order details

Vertical

Stacked panels suit content that benefits from height, such as a chart above the figures behind it. With orientation set to "vertical", users divide the height between the panels, so the element around the group needs a height of its own.

Orders
Order details

With Handle

A visible grip makes the handle easy to find for users who rarely change a layout. The grip appears through withHandle and marks the place where a drag begins.

Orders
Order details

Nested

A panel can hold a group of its own and divide its area along the other axis. Users then resize each level independently, for example the width of a sidebar and the height of two areas beside it.

Stores
Orders
Order details

Minimum Size

Some content loses its use below a certain size. Through minSize a panel keeps at least that size, and the handle stops as soon as the panel reaches it.

Orders
Order details

Maximum Size

A panel that grows without limit can push its neighbors out of view. Through maxSize it stops at a largest size, and the panels beside it keep the remaining space.

Orders
Order details

Panel Preview Mode

Users judge a new layout best while they are still dragging. The panels therefore follow every movement of the pointer, which is the default behavior of resizePreviewMode with the value "panel".

Orders
Order details

Separator Preview Mode

Panels with extensive content, such as large tables or charts, react more calmly when they change size only once. With the value "separator" of resizePreviewMode, a preview of the handle follows the pointer, and the panels take their new size when users release it.

Orders
Order details

Custom Preview

In separator mode, a drag shows a translucent copy of the handle by default. The preview prop of the handle replaces it with an element of its own, so the preview fits the product and marks where the panels will divide.

Orders
Order details

Larger Resize Target

A thin handle is hard to hit, especially on a touch screen. Through resizeTargetMinimumSize the area that starts a resize grows beyond the visible line, with separate sizes for a mouse and for touch input.

Orders
Order details

Without Resize Cursor

The group shows a resize cursor over a handle so that users recognize it as something to drag. Through disableCursor it keeps the regular pointer instead, and resizing works as before.

Orders
Order details

Without Double-Click Reset

A double-click on a handle returns a panel to its default size and lets users undo their changes in one step. Where a layout should stay exactly as users left it, disableDoubleClick turns this reset off.

Orders
Order details

Layout While Resizing

Some interfaces react to the layout while users are still dragging, for example to adapt content to the space it receives. For this purpose, onLayoutChange reports the size of every panel with each movement of the pointer.

Stores 50%
Transfers 50%

Layout After Resizing

A layout that users have arranged deserves to be kept for their next visit. The final layout arrives through onLayoutChanged once users release the pointer, so the application saves it once per change.

Products 50%
Prices 50%

Current Panel Size

Content can adapt to the room its panel offers, for example with more columns in a wider panel. Through onResize a panel reports its size in pixels and as a percentage whenever it changes.

Orders
Order details

Disabled Group

Some layouts must stay fixed, for example while a process works on the data they show. The disabled prop of the group then locks every panel, for the pointer as well as for the keyboard.

Orders
Order details

Disabled Panel

Within a flexible layout, one area can keep its size, such as a navigation with a fixed width. Set on a single panel, disabled holds that size whichever handle users drag, and the other panels share the remaining space.

Stores
Orders
Details

Disabled Handle

Sometimes only one boundary of a layout should stay in place. Users can no longer drag a handle that carries disabled, and keyboard focus passes over it, while the other handles still resize their panels.

Stores
Orders
Details

API Reference

ResizablePanelGroup

Proporientation
Type"horizontal" | "vertical"
Default"horizontal"
DescriptionSets the axis along which the panels are laid out and resized. A horizontal group places the panels side by side, and users change their widths. A vertical group stacks them, and users change their heights.
PropdefaultLayout
TypeLayout
Default–
DescriptionSets the sizes of the panels at first render as an object that maps each panel id to a percentage from 0 to 100. The group applies it only when its keys are exactly the ids of the panels, and it then takes precedence over defaultSize.
ProponLayoutChange
Type(layout: Layout) => void
Default–
DescriptionRuns when the layout changes and receives the layout that follows. During a drag, it runs on every pointer move. It also runs once with the first layout after the group mounts.
ProponLayoutChanged
Type(layout: Layout, meta: LayoutChangedMeta) => void
Default–
DescriptionRuns after the layout has changed. During a drag, it waits until users release the pointer, which suits saving a layout. In meta, isUserInteraction tells whether pointer or keyboard input caused the change, and requestedLayout holds the layout before the constraints of the current group size were applied.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from resizing the panels of the group with the pointer or the keyboard.
PropdisableCursor
Typeboolean
Defaultfalse
DescriptionTurns off the resize cursors that the group sets while the pointer is over a handle or drags it.
PropresizePreviewMode
Type"panel" | "separator"
Default"panel"
DescriptionSets what a drag changes before users release the pointer. With "panel", the panels resize at once. With "separator", a preview of the handle follows the pointer, and the panels resize when users release it.
PropresizeTargetMinimumSize
Type{ coarse: number; fine: number }
Default{ coarse: 20, fine: 10 }
DescriptionSets the smallest size, in pixels, of the area around a handle or a panel edge that starts a resize. coarse applies when the primary pointer is coarse, as on a touch screen, and fine applies otherwise, as with a mouse. A handle that is thinner than the value responds within that area.
PropgroupRef
TypeRef<GroupImperativeHandle | null>
Default–
DescriptionReceives the imperative API of the group. getLayout returns the current layout, and setLayout applies a layout and returns the layout that results from the constraints of the panels.
PropelementRef
TypeRef<HTMLDivElement | null>
Default–
DescriptionReceives the div that the group renders.
Propid
Typestring | number
Default–
DescriptionIdentifies the group. The group also sets it as the id and data-testid attributes of its div. Without it, the group generates an id.

ResizablePanel

PropdefaultSize
Typenumber | string
Default–
DescriptionSets the size of the panel at first render. A number counts as pixels, a string without a unit as a percentage of the group, and a string with a unit as that unit: %, px, em, rem, vh or vw. Panels without it share the remaining space equally.
PropminSize
Typenumber | string
Default"0%"
DescriptionSets the smallest size that the panel can take. It accepts the same formats as defaultSize.
PropmaxSize
Typenumber | string
Default"100%"
DescriptionSets the largest size that the panel can take. It accepts the same formats as defaultSize.
Propcollapsible
Typeboolean
Defaultfalse
DescriptionLets the panel collapse to collapsedSize when users resize it below minSize. Users expand it by dragging the handle back. While a handle has focus, Enter collapses or expands the collapsible panel before it.
PropcollapsedSize
Typenumber | string
Default"0%"
DescriptionSets the size of the panel while it is collapsed. It accepts the same formats as defaultSize.
PropcollapsedThreshold
Typenumber | string
Default–
DescriptionSets how far users drag a collapsible panel below minSize before it collapses, and above collapsedSize before it expands. Without it, the threshold is half the distance between collapsedSize and minSize. It accepts the same formats as defaultSize.
PropgroupResizeBehavior
Type"preserve-relative-size" | "preserve-pixel-size"
Default"preserve-relative-size"
DescriptionSets what the panel keeps when the group itself changes size. With "preserve-relative-size", the panel keeps its percentage of the group. With "preserve-pixel-size", it keeps its size in pixels as far as minSize and maxSize allow. A group needs at least one panel with "preserve-relative-size".
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents the panel from changing size, whether users drag a handle beside it or resize another panel.
ProponResize
Type(panelSize: PanelSize, id: string | number | undefined, prevPanelSize: PanelSize | undefined) => void
Default–
DescriptionRuns when the size of the panel changes, and once after the panel mounts. It receives the size as an object with asPercentage and inPixels, the id of the panel if the id prop is set, and the previous size, which is undefined at the first call.
ProppanelRef
TypeRef<PanelImperativeHandle | null>
Default–
DescriptionReceives the imperative API of the panel. collapse and expand change a collapsible panel, isCollapsed tells whether it is collapsed, getSize returns the size with asPercentage and inPixels, and resize sets a size in the formats of defaultSize.
PropelementRef
TypeRef<HTMLDivElement | null>
Default–
DescriptionReceives the outer div of the panel, which the group sizes.
Propid
Typestring | number
Default–
DescriptionIdentifies the panel within its group. The keys of defaultLayout and of the layouts that the callbacks receive are panel ids. The panel also sets it as the id and data-testid attributes of its outer div. Without it, the panel generates an id.
PropclassName
Typestring
Default–
DescriptionAdds classes to the inner div that holds the content. The outer div is the flex item that the group sizes, and it takes no classes.
Propstyle
TypeCSSProperties
Default–
DescriptionSets inline styles on the inner div that holds the content. That div scrolls its content with overflow "auto" unless style sets another value.

ResizableHandle

PropwithHandle
Typeboolean
Defaultfalse
DescriptionShows a grip in the middle of the handle, so that users see where to drag.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from resizing the neighboring panels with this handle and removes the handle from the tab order. The panels can still change size when users drag another handle.
PropdisableDoubleClick
Typeboolean
Defaultfalse
DescriptionTurns off the reset on double-click. Without it, a double-click on the handle returns the first neighboring panel that has a defaultSize to that size.
Proppreview
TypeReactNode
Default–
DescriptionSets the element that follows the pointer while users drag this handle in a group with resizePreviewMode set to "separator". Without it, the group shows a translucent copy of the handle.
PropelementRef
TypeRef<HTMLDivElement>
Default–
DescriptionReceives the div that the handle renders.
Propid
Typestring | number
Default–
DescriptionIdentifies the handle within its group. The handle also sets it as the id and data-testid attributes of its div. Without it, the handle generates an id.