Skip to Content
ReferenceComponents

<NodeResizer />

Source on GitHub 

The <NodeResizer /> component can be used to add a resize functionality to your nodes. It renders draggable controls around the node to resize in all directions.

import { memo } from 'react'; import { Handle, Position, NodeResizer } from '@xyflow/react'; const ResizableNode = ({ data }) => { return ( <> <NodeResizer minWidth={100} minHeight={30} /> <Handle type="target" position={Position.Left} /> <div style={{ padding: 10 }}>{data.label}</div> <Handle type="source" position={Position.Right} /> </> ); }; export default memo(ResizableNode);

Props

For TypeScript users, the props type for the <NodeResizer /> component is exported as NodeResizerProps.

NameTypeDefault
nodeIdstring

Id of the node it is resizing.

colorstring

Color of the resize handle.

handleClassNamestring

Class name applied to handle.

handleStyleCSSProperties

Style applied to handle.

lineClassNamestring

Class name applied to line.

lineStyleCSSProperties

Style applied to line.

isVisibleboolean

Are the controls visible.

true
minWidthnumber

Minimum width of node.

10
minHeightnumber

Minimum height of node.

10
maxWidthnumber

Maximum width of node.

Number.MAX_VALUE
maxHeightnumber

Maximum height of node.

Number.MAX_VALUE
keepAspectRatioboolean

Keep aspect ratio when resizing.

false
autoScaleboolean

Scale the controls with the zoom level.

true
shouldResize(event: ResizeDragEvent, params: ResizeParamsWithDirection) => boolean

Callback to determine if node should resize.

onResizeStartOnResizeStart

Callback called when resizing starts.

onResizeOnResize

Callback called when resizing.

onResizeEndOnResizeEnd

Callback called when resizing ends.

Examples

Head over to the example page to see how this is done.

/* xyflow theme files. Delete these to start from our base */ .react-flow { --xy-background-color: #f7f9fb; /* Custom Variables */ --xy-theme-selected: #f57dbd; --xy-theme-hover: #c5c5c5; --xy-theme-edge-hover: black; --xy-theme-color-focus: #e8e8e8; /* Built-in Variables see https://reactflow.dev/learn/customization/theming */ --xy-node-border-default: 1px solid #ededed; --xy-node-boxshadow-default: 0px 3.54px 4.55px 0px #00000005, 0px 3.54px 4.55px 0px #0000000d, 0px 0.51px 1.01px 0px #0000001a; --xy-node-border-radius-default: 8px; --xy-handle-background-color-default: #ffffff; --xy-handle-border-color-default: #aaaaaa; --xy-edge-label-color-default: #505050; --xy-node-background-color-default: #ffffff; --xy-theme-panel-bg: #ffffff; --xy-theme-panel-text: #111827; --xy-theme-resize-handle-bg: #ffffff; --xy-theme-focus-border: #d9d9d9; --xy-theme-muted-bg: #f3f4f6; --xy-theme-subtle-border: #d1d5db; } .react-flow.dark { --xy-background-color: #101012; --xy-node-background-color-default: #1a1b1e; --xy-node-border-default: 1px solid #303238; --xy-handle-background-color-default: #141519; --xy-handle-border-color-default: #5a5d66; --xy-edge-label-color-default: #e6e7ea; --xy-theme-hover: #7a7d86; --xy-theme-edge-hover: #f3f4f6; --xy-theme-panel-bg: #141519; --xy-theme-panel-text: #f3f4f6; --xy-theme-resize-handle-bg: #141519; --xy-theme-focus-border: #5f6470; --xy-theme-muted-bg: #24262c; --xy-theme-subtle-border: #3f434c; --xy-node-boxshadow-default: none; --xy-theme-color-focus: #4b4e57; --color-background: #1a1b1e; --color-hover-bg: #24262c; --color-disabled: #8b9099; } .react-flow { background-color: var(--xy-background-color); } /* Customizing Default Theming */ .react-flow__node { box-shadow: var(--xy-node-boxshadow-default); border-radius: var(--xy-node-border-radius-default); background-color: var(--xy-node-background-color-default); display: flex; justify-content: center; align-items: center; text-align: center; padding: 10px; font-size: 12px; flex-direction: column; border: var(--xy-node-border-default); color: var(--xy-node-color, var(--xy-node-color-default)); } .react-flow__node.selectable:focus { box-shadow: 0px 0px 0px 4px var(--xy-theme-color-focus); border-color: var(--xy-theme-focus-border); } .react-flow__node.selectable:focus:active { box-shadow: var(--xy-node-boxshadow-default); } .react-flow__node.selectable:hover, .react-flow__node.draggable:hover { border-color: var(--xy-theme-hover); } .react-flow__node.selectable.selected { border-color: var(--xy-theme-selected); box-shadow: var(--xy-node-boxshadow-default); } .react-flow__node-group { background-color: rgba(207, 182, 255, 0.4); border-color: #9e86ed; } .react-flow.dark .react-flow__node-group { background-color: rgba(123, 107, 148, 0.22); border-color: #7b6b94; } .react-flow__edge.selectable:hover .react-flow__edge-path, .react-flow__edge.selectable.selected .react-flow__edge-path { stroke: var(--xy-theme-edge-hover); } .react-flow__handle { background-color: var(--xy-handle-background-color-default); } .react-flow__handle.connectionindicator:hover { pointer-events: all; border-color: var(--xy-theme-edge-hover); background-color: var(--xy-handle-background-color-default); } .react-flow__handle.connectionindicator:focus, .react-flow__handle.connectingfrom, .react-flow__handle.connectingto { border-color: var(--xy-theme-edge-hover); } .react-flow__node-resizer { border-radius: 0; border: none; } .react-flow__resize-control.handle { background-color: var(--xy-theme-resize-handle-bg); border-color: #9e86ed; border-radius: 0; width: 5px; height: 5px; } /* Custom Example CSS - This CSS is to improve the example experience. You can remove it if you want to use the default styles. New Theme Classes: .xy-theme__button - Styles for buttons. .xy-theme__input - Styles for text inputs. .xy-theme__checkbox - Styles for checkboxes. .xy-theme__select - Styles for dropdown selects. .xy-theme__label - Styles for labels. Use these classes to apply consistent theming across your components. */ :root { --color-primary: #ff0073; --color-background: #fefefe; --color-hover-bg: #f6f6f6; --color-disabled: #76797e; } .xy-theme__button-group { display: flex; align-items: center; .xy-theme__button:first-child { border-radius: 100px 0 0 100px; } .xy-theme__button:last-child { border-radius: 0 100px 100px 0; margin: 0; } } /* Custom Button Styling */ .xy-theme__button { display: inline-flex; align-items: center; justify-content: center; height: 2.5rem; padding: 0 1rem; border-radius: 100px; border: 1px solid var(--color-primary); background-color: var(--color-background); color: var(--color-primary); transition: background-color 0.2s ease, border-color 0.2s ease; box-shadow: var(--xy-node-boxshadow-default); cursor: pointer; } .xy-theme__button.active { background-color: var(--color-primary); color: white; border-color: var(--color-primary); } .xy-theme__button.active:hover, .xy-theme__button.active:active { background-color: var(--color-primary); opacity: 0.9; } .xy-theme__button:hover { background-color: var(--xy-controls-button-background-color-hover-default); } .xy-theme__button:active { background-color: var(--color-hover-bg); } .xy-theme__button:disabled { color: var(--color-disabled); opacity: 0.8; cursor: not-allowed; border: 1px solid var(--color-disabled); } .xy-theme__button > span { margin-right: 0.2rem; } /* Add gap between adjacent buttons */ .xy-theme__button + .xy-theme__button { margin-left: 0.3rem; } /* Example Input Styling */ .xy-theme__input { padding: 0.5rem 0.75rem; border: 1px solid var(--color-primary); border-radius: 7px; background-color: var(--color-background); transition: background-color 0.2s ease, border-color 0.2s ease; font-size: 1rem; color: var(--xy-theme-panel-text); } .xy-theme__input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 2px rgba(255, 0, 115, 0.3); } /* Specific Checkbox Styling */ .xy-theme__checkbox { appearance: none; -webkit-appearance: none; width: 1.25rem; height: 1.25rem; border-radius: 7px; border: 2px solid var(--color-primary); background-color: var(--color-background); transition: background-color 0.2s ease, border-color 0.2s ease; cursor: pointer; display: inline-block; vertical-align: middle; margin-right: 0.5rem; } .xy-theme__checkbox:checked { background-color: var(--color-primary); border-color: var(--color-primary); } .xy-theme__checkbox:focus { outline: none; box-shadow: 0 0 0 2px rgba(255, 0, 115, 0.3); } /* Dropdown Styling */ .xy-theme__select { padding: 0.5rem 0.75rem; border: 1px solid var(--color-primary); border-radius: 50px; background-color: var(--color-background); transition: background-color 0.2s ease, border-color 0.2s ease; font-size: 1rem; color: var(--xy-theme-panel-text); margin-right: 0.5rem; box-shadow: var(--xy-node-boxshadow-default); } .xy-theme__select:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 2px rgba(255, 0, 115, 0.3); } .xy-theme__label { margin-top: 10px; margin-bottom: 3px; display: inline-block; color: var(--xy-theme-panel-text); }

Custom Resize Controls

To build custom resize controls, you can use the NodeResizeControl component and customize it.

Notes

  • Take a look at the docs for the NodeProps type or the guide on custom nodes to see how to implement your own nodes.
Last updated on