ResizeHandle manages a numeric size and exposes a focusable separator. The application applies that size to the panel; the handle does not resize another element automatically.
Usage
Useedge for a panel boundary, or axis="y" for inline height resizing and axis="x" for inline width resizing. Give the handle a specific accessible name and use aria-controls to identify the panel.
onValueChange copies the latest size to the panel layout without controlling the handle. defaultValue only sets the initial size.
Controlled state
value; use onValueCommitted to save the final size. Keep value and defaultValue separate and retain the same ownership mode throughout the component’s lifetime.
Panel edges and gaps
edge="left", "right", "top" or "bottom" determines both the axis and the physical increasing direction. Leftward movement grows a left edge, upward movement grows a top edge, and the opposite applies to right and bottom edges. This behavior stays the same in right-to-left content. Use either edge or axis and direction.
With edge, placement defaults to "edge". Put the handle inside a panel with position: 'relative' to position it along that boundary. placement="inline" keeps it in normal flow. Use placement="gap" between sibling panels and set its width or height through style when the layout needs a gap. Gap handles have no visible grip by default.
onActivate for an optional collapse action.
Keyboard and bounds
Foraxis="y", Down increases the size and Up decreases it. For axis="x", Right increases and Left decreases in left-to-right content; the directions reverse under DirectionProvider with direction="rtl".
Arrow keys use step, which defaults to 10. Home moves to min, and End moves to max. Keys pressed with Alt, Control or Meta are ignored. Pointer dragging uses the pixel movement and is not snapped to step. Both interactions stay within the bounds. Pointer presses do not move focus; keyboard users reach the handle with Tab. disabled prevents resizing and removes the handle from the tab order.
The separator orientation describes the dividing edge: horizontal for height resizing and vertical for width resizing.
Physical directions and zoom
Setdirection="normal" or direction="reverse" when increasing size must follow a fixed physical direction, regardless of text direction. Normal increases with rightward or downward movement. Reverse increases with leftward or upward movement. Omit direction to retain the text-direction behavior described above.
scale accepts a positive zoom factor or a function returning one. The handle samples it at pointer down and divides pointer movement by that value. Keyboard steps remain unchanged.
Gesture lifecycle
onValueChange reports live values. onValueCommitted reports the final value after a successful pointer drag or an effective keyboard change. Home, End and arrow keys commit immediately when they change the size.
onResizeStart receives the first bounded candidate after the pointer passes dragThreshold. The threshold defaults to 5 with edge and 0 otherwise, measured in physical pixels. onResizeEnd receives { cancelled, value } for a started drag. Escape, pointer cancellation, lost pointer capture and unmounting cancel the gesture without committing; disabling the handle cancels it on its next pointer event. Cancellation calls onValueChange with the starting value, clamped to the current bounds. onResizeEnd receives that restored value.
Supply onActivate to handle a click without dragging, Enter or Space. Crossing the threshold prevents the following pointer click from activating, even when the pointer returns to its starting position.
Native handlers run before the handle’s interaction. Calling preventDefault() in onPointerDown or onKeyDown skips that interaction. Preventing onPointerMove skips only that update and leaves the gesture active. Preventing onPointerUp cancels the drag, restores the starting bounded value and skips onValueCommitted. Pointer cancellation and lost capture still end the gesture.
Custom handle
ref, native attributes, className, style and native event handlers target the separator root, a div by default. The ref does not target the resized panel or the visible grip.
children replaces the visible grip, and children={null} hides it; it does not replace the separator behavior. render can replace the root element, and the ref then targets that replacement. Custom wrappers must forward the supplied props and ref so focus, pointer capture, keyboard handlers, and accessibility attributes reach the same element.
Props
"x" | "y"
default:"y without edge"
Pointer movement axis without
edge: y for height or x for width.number | (readonly string[] & number)
default:"150"
Initial size when the handle owns its state.
"normal" | "reverse"
Physical increasing direction. Omit to follow the horizontal text direction; use
normal or reverse for a fixed physical edge.boolean
default:"false"
Disables resizing and removes the handle from the tab order.
number
default:"5 with edge; 0 otherwise"
Physical pointer distance required before resizing starts. Movement below the threshold remains a click. Defaults to 5 with
edge and 0 otherwise."bottom" | "left" | "right" | "top"
Physical panel edge. Determines the movement axis and increasing direction, independently of text direction.
number
default:"500"
Maximum allowed size.
number
default:"50"
Minimum allowed size.
(() => void)
Called for a click without dragging, Enter, or Space.
((details: { cancelled: boolean; value: number; }) => void)
Called after a started drag ends, with its final value and whether it was cancelled. Cancellation restores the starting value within the current bounds.
((value: number) => void)
Called once with the first bounded drag value after the threshold is crossed.
((value: number) => void)
Called with the bounded size during pointer or keyboard interaction and with the restored value on cancellation.
((value: number) => void)
Called with the final size after a successful drag or an effective keyboard size change. Cancellation does not commit.
"edge" | "gap" | "inline"
default:"edge with edge; inline otherwise"
Layout mode:
inline stays in normal flow, edge positions the handle on the panel edge, and gap sits between panels. Defaults to edge when edge is set and inline otherwise.ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>
Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a
ReactElement or a function that returns the element to render.number | (() => number)
default:"1"
Pointer scale or resolver sampled at pointer down. Movement is divided by this positive scale; keyboard steps are unchanged.
number
default:"10"
Keyboard arrow increment. Pointer movement uses the pixel delta.
number
Current controlled size. Update it in
onValueChange and apply it to the element being resized.