Theme

Customize appearance

Components

Resizable

Let users adjust the space allocated to neighboring panels.

View component source ↗

Preview

A minimal example to get started.

Left
Right

Installation

Install this component and its dependencies in a project initialized with shadcn.

pnpm dlx shadcn@latest add https://ui.hyunjoon.net/r/resizable.json

Usage

This is the basic example. Use the Code tab above for the selected example. Adjust import aliases to match your project.

import {
  ResizablePanelGroup,
  ResizablePanel,
  ResizableHandle,
} from "@/components/ui/resizable";

export default function Example() {
  return (
    <ResizablePanelGroup orientation="horizontal" className="min-h-40 max-w-sm rounded-lg border">
      <ResizablePanel defaultSize="50%">
        <div className="flex h-full items-center justify-center p-4">Left</div>
      </ResizablePanel>
      <ResizableHandle withHandle />
      <ResizablePanel defaultSize="50%">
        <div className="flex h-full items-center justify-center p-4">Right</div>
      </ResizablePanel>
    </ResizablePanelGroup>
  );
}

API reference

Derived from the installed component types. Native DOM props are also supported where applicable. A dash means no explicit default is documented. Some props depend on the selected mode.

ResizableHandle
ResizableHandle properties
PropTypeDefaultDescription
className
string | undefined
string | undefined
—CSS class name. ℹ️ Use the `data-separator` attribute for custom _hover_ and _active_ styles ⚠️ The following properties cannot be overridden: `flex-grow`, `flex-shrink`
defaultValue
string | number | readonly string[] | undefined
string | number | readonly string[] | undefined
—Initial value for an uncontrolled component.
defaultChecked
boolean | undefined
boolean | undefined
—Initial checked state for an uncontrolled control.
style
React.CSSProperties | undefined
React.CSSProperties | undefined
—CSS properties. ℹ️ Use the `data-separator` attribute for custom _hover_ and _active_ styles ⚠️ The following properties cannot be overridden: `flex-grow`, `flex-shrink`
id
string | undefined
string | undefined
—Uniquely identifies the separator within the parent group. Falls back to `useId` when not provided. ℹ️ This value will also be assigned to the `data-separator` attribute.
children
React.ReactNode
React.ReactNode
—Content rendered inside this component.
onFocus
React.FocusEventHandler<HTMLDivElement> | undefined
React.FocusEventHandler<HTMLDivElement> | undefined
—Called when the control receives focus.
onBlur
React.FocusEventHandler<HTMLDivElement> | undefined
React.FocusEventHandler<HTMLDivElement> | undefined
—Called when the control loses focus.
onChange
React.ChangeEventHandler<HTMLDivElement, Element> | undefined
React.ChangeEventHandler<HTMLDivElement, Element> | undefined
—Called when the underlying form control changes; inspect the event for its value.
onKeyDown
React.KeyboardEventHandler<HTMLDivElement> | undefined
React.KeyboardEventHandler<HTMLDivElement> | undefined
—Called when a key is pressed while this element is focused.
onClick
React.MouseEventHandler<HTMLDivElement> | undefined
React.MouseEventHandler<HTMLDivElement> | undefined
—Called when the element is activated.
disabled
boolean | undefined
boolean | undefined
—When disabled, the separator cannot be used to resize its neighboring panels. ℹ️ The panels may still be resized indirectly (while other panels are being resized). To prevent a panel from being resized at all, it needs to also be disabled.
disableDoubleClick
boolean | undefined
boolean | undefined
—When true, double-clicking this `Separator` will not reset its `Panel` to its default size.
elementRef
React.Ref<HTMLDivElement> | undefined
React.Ref<HTMLDivElement> | undefined
—Ref attached to the root `HTMLDivElement`.
withHandle
boolean | undefined
boolean | undefined
—Displays a visible grip on the resize handle.
ResizablePanel
ResizablePanel properties
PropTypeDefaultDescription
className
string | undefined
string | undefined
—CSS class name. ⚠️ Class is applied to nested `HTMLDivElement` to avoid styles that interfere with Flex layout.
defaultValue
string | number | readonly string[] | undefined
string | number | readonly string[] | undefined
—Initial value for an uncontrolled component.
defaultChecked
boolean | undefined
boolean | undefined
—Initial checked state for an uncontrolled control.
style
React.CSSProperties | undefined
React.CSSProperties | undefined
—CSS properties. ⚠️ Style is applied to nested `HTMLDivElement` to avoid styles that interfere with Flex layout.
id
string | undefined
string | undefined
—Uniquely identifies this panel within the parent group. Falls back to `useId` when not provided. ℹ️ This prop is used to associate persisted group layouts with the original panel. ℹ️ This value will also be assigned to the `data-panel` attribute.
children
React.ReactNode
React.ReactNode
—Content rendered inside this component.
onFocus
React.FocusEventHandler<HTMLDivElement> | undefined
React.FocusEventHandler<HTMLDivElement> | undefined
—Called when the control receives focus.
onBlur
React.FocusEventHandler<HTMLDivElement> | undefined
React.FocusEventHandler<HTMLDivElement> | undefined
—Called when the control loses focus.
onChange
React.ChangeEventHandler<HTMLDivElement, Element> | undefined
React.ChangeEventHandler<HTMLDivElement, Element> | undefined
—Called when the underlying form control changes; inspect the event for its value.
onKeyDown
React.KeyboardEventHandler<HTMLDivElement> | undefined
React.KeyboardEventHandler<HTMLDivElement> | undefined
—Called when a key is pressed while this element is focused.
onClick
React.MouseEventHandler<HTMLDivElement> | undefined
React.MouseEventHandler<HTMLDivElement> | undefined
—Called when the element is activated.
collapsedSize
string | number | undefined
string | number | undefined
—Panel size when collapsed; defaults to 0%.
collapsible
boolean | undefined
boolean | undefined
—This panel can be collapsed. ℹ️ A collapsible panel will collapse when it's size is less than of the specified `minSize`
defaultSize
string | number | undefined
string | number | undefined
—Default size of Panel within its parent group; default is auto-assigned based on the total number of Panels. ℹ️ Interpretation rules: - Numbers are interpreted as pixels (e.g. `defaultSize={200}` is 200 pixels) - Strings without explicit units are interpreted as percentage (e.g. `defaultSize="50"` is 50 percent) - Use explicit units (e.g. "px", "%", "em", "rem", "vh", or "vw") to change interpretation ⚠️ Percentage based sizes may cause slight layout shift when server-rendering. For more information see the documentation.
disabled
boolean | undefined
boolean | undefined
—When disabled, a panel cannot be resized either directly or indirectly (by resizing another panel).
elementRef
React.Ref<HTMLDivElement | null> | undefined
React.Ref<HTMLDivElement | null> | undefined
—Ref attached to the root `HTMLDivElement`.
groupResizeBehavior
"preserve-relative-size" | "preserve-pixel-size" | undefined
"preserve-relative-size" | "preserve-pixel-size" | undefined
—How should this Panel behave if the parent Group is resized? Defaults to `preserve-relative-size`. - `preserve-relative-size`: Retain the current relative size (as a percentage of the Group) - `preserve-pixel-size`: Retain its current size (in pixels) ℹ️ Panel min/max size constraints may impact this behavior. ⚠️ A Group must contain at least one Panel with `preserve-relative-size` resize behavior.
maxSize
string | number | undefined
string | number | undefined
—Maximum size of Panel within its parent group; defaults to `"100%"`. ℹ️ Interpretation rules: - Numbers are interpreted as pixels (e.g. `maxSize={200}` is 200 pixels) - Strings without explicit units are interpreted as percentage (e.g. `maxSize="50"` is 50 percent) - Use explicit units (e.g. "px", "%", "em", "rem", "vh", or "vw") to change interpretation
minSize
string | number | undefined
string | number | undefined
—Minimum size of Panel within its parent group; defaults to 0%. ℹ️ Interpretation rules: - Numbers are interpreted as pixels (e.g. `minSize={200}` is 200 pixels) - Strings without explicit units are interpreted as percentage (e.g. `minSize="50"` is 50 percent) - Use explicit units (e.g. "px", "%", "em", "rem", "vh", or "vw") to change interpretation
onResize
((panelSize: ResizablePrimitive.PanelSize, id: string | number | undefined, prevPanelSize:…
((panelSize: ResizablePrimitive.PanelSize, id: string | number | undefined, prevPanelSize: ResizablePrimitive.PanelSize | undefined) => void) | undefined
—Called when panel sizes change.
panelRef
React.Ref<ResizablePrimitive.PanelImperativeHandle | null> | undefined
React.Ref<ResizablePrimitive.PanelImperativeHandle | null> | undefined
—Exposes the following imperative API: - `collapse(): void` - `expand(): void` - `getSize(): number` - `isCollapsed(): boolean` - `resize(size: number): void` ℹ️ The `usePanelRef` and `usePanelCallbackRef` hooks are exported for convenience use in TypeScript projects.
ResizablePanelGroup
ResizablePanelGroup properties
PropTypeDefaultDescription
defaultChecked
boolean | undefined
boolean | undefined
—Initial checked state for an uncontrolled control.
defaultValue
string | number | readonly string[] | undefined
string | number | readonly string[] | undefined
—Initial value for an uncontrolled component.
className
string | undefined
string | undefined
—CSS class name.
id
string | undefined
string | undefined
—Uniquely identifies this group within an application. Falls back to `useId` when not provided. ℹ️ This value will also be assigned to the `data-group` attribute.
style
React.CSSProperties | undefined
React.CSSProperties | undefined
—CSS properties. ⚠️ The following styles cannot be overridden: `display`, `flex-direction`, `flex-wrap`, and `overflow`.
children
React.ReactNode
React.ReactNode
—Panel and Separator components that comprise this group.
onFocus
React.FocusEventHandler<HTMLDivElement> | undefined
React.FocusEventHandler<HTMLDivElement> | undefined
—Called when the control receives focus.
onBlur
React.FocusEventHandler<HTMLDivElement> | undefined
React.FocusEventHandler<HTMLDivElement> | undefined
—Called when the control loses focus.
onChange
React.ChangeEventHandler<HTMLDivElement, Element> | undefined
React.ChangeEventHandler<HTMLDivElement, Element> | undefined
—Called when the underlying form control changes; inspect the event for its value.
onKeyDown
React.KeyboardEventHandler<HTMLDivElement> | undefined
React.KeyboardEventHandler<HTMLDivElement> | undefined
—Called when a key is pressed while this element is focused.
onClick
React.MouseEventHandler<HTMLDivElement> | undefined
React.MouseEventHandler<HTMLDivElement> | undefined
—Called when the element is activated.
defaultLayout
ResizablePrimitive.Layout | undefined
ResizablePrimitive.Layout | undefined
—Default layout for the Group. ℹ️ This value allows layouts to be remembered between page reloads. ⚠️ Slight layout shift may occur when server-rendering panels with percentage-based default sizes. Refer to the documentation for suggestions on how to minimize the impact of this.
disableCursor
boolean | undefined
boolean | undefined
—This library sets custom mouse cursor styles to indicate drag state. Use this prop to disable that behavior for Panels and Separators in this group.
disabled
boolean | undefined
boolean | undefined
—Disable resize functionality.
elementRef
React.Ref<HTMLDivElement | null> | undefined
React.Ref<HTMLDivElement | null> | undefined
—Ref attached to the root `HTMLDivElement`.
groupRef
React.Ref<ResizablePrimitive.GroupImperativeHandle | null> | undefined
React.Ref<ResizablePrimitive.GroupImperativeHandle | null> | undefined
—Exposes the following imperative API: - `getLayout(): Layout` - `setLayout(layout: Layout): void` ℹ️ The `useGroupRef` and `useGroupCallbackRef` hooks are exported for convenience use in TypeScript projects.
onLayoutChange
((layout: ResizablePrimitive.Layout) => void | undefined) | undefined
((layout: ResizablePrimitive.Layout) => void | undefined) | undefined
—Called when the Group's layout is changing. ⚠️ For layout changes caused by pointer events, this method is called each time the pointer is moved. For most cases, it is recommended to use the `onLayoutChanged` callback instead.
onLayoutChanged
((layout: ResizablePrimitive.Layout, meta: ResizablePrimitive.LayoutChangedMeta) => void) …
((layout: ResizablePrimitive.Layout, meta: ResizablePrimitive.LayoutChangedMeta) => void) | undefined
—Called after the Group's layout has been changed. ℹ️ For layout changes caused by pointer events, this method is not called until the pointer has been released. This method is recommended when saving layouts to some storage api. ℹ️ The second argument contains meta information about the layout change. The `isUserInteraction` attribute signals whether the resize was caused by direct user input. It is true for resizes caused by pointer or keyboard input and false for other triggers (e.g. imperative API calls, initial mount, etc.)
resizeTargetMinimumSize
{ coarse: number; fine: number; } | undefined
{ coarse: number; fine: number; } | undefined
—Minimum size of the resizable hit target area (either `Separator` or `Panel` edge) This threshold ensures are large enough to avoid mis-clicks. - Coarse inputs (typically a finger on a touchscreen) have reduced accuracy; to ensure accessibility and ease of use, hit targets should be larger to prevent mis-clicks. - Fine inputs (typically a mouse) can be smaller ℹ️ [Apple interface guidelines](https://developer.apple.com/design/human-interface-guidelines/accessibility) suggest `20pt` (`27px`) on desktops and `28pt` (`37px`) for touch devices In practice this seems to be much larger than many of their own applications use though.
orientation
"horizontal" | "vertical" | undefined
"horizontal" | "vertical" | undefined
—Specifies the resizable orientation ("horizontal" or "vertical"); defaults to "horizontal"

Usage notes

Place handles between panels in a panel group. Give the container a useful size and set minimum panel sizes when content requires them.