@crustack/resizable
Headless components for creating resizable elements.
Headless components for creating resizable elements.
Quick Start
Define the resizable components
Create a resizable element with the Root component.
You should provide boundary constraints like minHeight, maxHeight, minWidth, and maxWidth to control resizing behavior.
Add Resize Handles with the Handle component.
The Handle component lets you add draggable handles for resizing.
- The
ratioprop defines which direction the resizing occurs (e.g., horizontally, vertically, or both). - The
cursorprop defines the cursor style during the resize operation and ensures consistency by applying it to both the handle and the body when the handle is active.
Here's how to add handles for different sides and corners:
Examples
1. Left aligned Sidebar
This example demonstrates how to build a Left aligned resizable sidebar.
2. Right aligned Sidebar
Building off the Left aligned Sidebar example,we will modify the handle's position and the resize behavior to create a Right-aligned sidebar.
By default, if you place the handle on the left side of the Root, resizing behaves inversely
to what you'd expect. To fix this, we'll use the ratio prop to invert the width calculations.
3. Resize Direction & Centered elements
When working with elements that are centered, using a ratio of 1 or -1 will cause
the handle to move at half the speed of the mouse. This happens because the handle is
centered, and the resizing effect is spread across both sides of the element.
To fix this behavior, you should use ratio values of 2 or -2, effectively doubling
the movement of the handle so it matches the mouse speed.
As a general rule:
- use a negative ratio for top and left handles
- use a positive ratio for bottom and right handles
The following example demonstrates how to apply the ratio for all possible handle positions:
4. Usage with Tailwind
You might want to leverage Tailwind to define the initial size of your elements, particularly when adjusting sizes across breakpoints and media queries.
This can be done by omitting the width and/or height properties from the
initial size object, allowing Tailwind classes to dictate the initial dimensions.
5. Improving Performance
Resizing DOM elements can be performance-intensive because each size change triggers a browser reflow and repaint. To minimize this, you can use the resizable element as a mask, following these steps:
- Set a positioning context (e.g. "relative") for the element you want to resize.
- disable
flex-shrinkto prevent unexpected behaviors. - Position the
RootandHandle(s) on top of the target element, matching its size. - Disable pointer events on the
Rootbut re-enable them on theHandle(s) for interactivity. - Update the width of the target element using the
onResizeEndevent.
API Reference
👉 resizable.Root
The resizable element
Props
| Prop | Type | Default |
|---|---|---|
size | Size | - |
onResizeEnd? | (() => void) | - |
onResize? | ((size: MeasuredSize) => void) | - |
locked? | boolean | - |
children? | ReactNode | ((props: Size & { isResizing: boolean; }) => ReactNode) | - |
asChild? | boolean | - |
Data Attributes
| Prop | Type | Default |
|---|---|---|
data-locked? | "true" | undefined | - |
data-resizing? | "true" | undefined | - |
data-resizable? | "true" | - |
👉 resizable.Handle
The Handles for resizing the Root element.
Props
| Prop | Type | Default |
|---|---|---|
onResizeEnd? | (() => void) | - |
onResize? | ((size: MeasuredSize) => void) | - |
ratio | Ratio | - |
cursor? | Cursor | - |
children? | ReactNode | ((props: { isActive: boolean; }) => ReactNode) | - |
asChild? | boolean | - |
Data Attributes
| Prop | Type | Default |
|---|---|---|
data-locked? | "true" | undefined | - |
data-active? | "true" | undefined | - |
data-handle? | "true" | - |