content/docs/api/resizable.mdx
@platejs/resizable provides the headless resize wrapper, resize handle primitive,
shared resize stores, and length utilities used by Plate media components. It
owns behavior; registry components own styling.
npm install @platejs/resizable
| Surface | Owner | Use |
|---|---|---|
Resizable | @platejs/resizable | Wraps a Plate element, tracks width, clamps resize values, and writes the final width to the node. |
ResizeHandle | @platejs/resizable | Primitive handle that starts mouse/touch resizing and emits ResizeEvent values. |
ResizableProvider | @platejs/resizable | Stores the active width for the current resizable subtree. |
ResizeHandleProvider | @platejs/resizable | Shares the wrapper onResize callback with nested handles. |
| Resize hooks | @platejs/resizable | Split state from DOM props for custom wrappers and handles. |
| Length utilities | @platejs/resizable | Convert and clamp static pixel widths and relative percent widths. |
Wrap each resizable element with ResizableProvider. Media components use the
provider width for captions and use Resizable plus left/right handles around
the media body.
import type { TImageElement } from 'platejs';
import type { PlateElementProps } from 'platejs/react';
import {
Resizable,
ResizableProvider,
ResizeHandle,
useResizableValue,
} from '@platejs/resizable';
import { PlateElement, withHOC } from 'platejs/react';
export const ImageElement = withHOC(
ResizableProvider,
function ImageElement(props: PlateElementProps<TImageElement>) {
const width = useResizableValue('width');
return (
<PlateElement {...props}>
<figure contentEditable={false}>
<Resizable
options={{
align: 'center',
maxWidth: '100%',
minWidth: 120,
}}
>
<ResizeHandle options={{ direction: 'left' }} />
<ResizeHandle options={{ direction: 'right' }} />
</Resizable>
<figcaption style={{ width }}>Caption</figcaption>
</figure>
{props.children}
</PlateElement>
);
}
);
The registry resize-handle component imports these primitives and adds the absolute positioning, hover affordance, and alignment classes.
Resizable composes useResizableState and useResizable. It renders a
relative outer wrapper and a relative inner wrapper, then provides its resize
callback to descendants through ResizeHandleProvider.
For centered elements, left and right handles double the delta so the element grows from both sides. Left handles invert the delta before clamping.
ResizeHandle is a primitive div created with createPrimitiveComponent. It
returns null in read-only mode because useResizeHandle sets hidden from
useReadOnly().
Resize handles listen on window while dragging. Mouse and touch move events emit finished: false; mouse up and touch end emit finished: true.
| API | State | Use |
|---|---|---|
ResizableProvider | { width: React.CSSProperties['width'] } | Wrap a resizable node and expose the active width to captions or overlays. |
useResizableValue('width') | React.CSSProperties['width'] | Read the current width. |
useResizableSet('width') | setter | Set the current width. |
useResizableStore / resizableStore | atom store | Advanced access to the resizable store. |
ResizeHandleProvider | { onResize: (event: ResizeEvent) => void } | Provides the wrapper resize callback to nested handles. |
useResizeHandleValue('onResize') | callback | Read the current resize callback. |
useResizeHandleSet('onResize') | setter | Replace the current resize callback. |
useResizeHandleStore | atom store | Advanced access to the handle store. |
| Type | Value |
|---|---|
ResizeDirection | 'bottom' | 'left' | 'right' | 'top' |
ResizeLength | number | string |
ResizeLengthStatic | number |
ResizeLengthRelative | string |
ResizeEvent | { delta: number; direction: ResizeDirection; finished: boolean; initialSize: number } |
resizeLengthToStatic parses strings as percentages. Use numeric pixel lengths when the source value is not a percentage.