<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.

  • nodeId?: string Id of the node it is resizing.
  • color?: string Color of the resize handle.
  • handleClassName?: string Class name applied to handle.
  • handleStyle?: CSSProperties Style applied to handle.
  • lineClassName?: string Class name applied to line.
  • lineStyle?: CSSProperties Style applied to line.
  • isVisible?: boolean Are the controls visible.
  • minWidth?: number Minimum width of node.
  • minHeight?: number Minimum height of node.
  • maxWidth?: number Maximum width of node.
  • maxHeight?: number Maximum height of node.
  • keepAspectRatio?: boolean Keep aspect ratio when resizing.
  • autoScale?: boolean Scale the controls with the zoom level.
  • shouldResize?: (event: ResizeDragEvent, params: ResizeParamsWithDirection) => boolean Callback to determine if node should resize.
  • onResizeStart?: OnResizeStart Callback called when resizing starts.
  • onResize?: OnResize Callback called when resizing.
  • onResizeEnd?: OnResizeEnd Callback called when resizing ends.

Examples

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

Example: examples/nodes/node-resizer

App.jsx
import {
  ReactFlow,
  Background,
  BackgroundVariant,
  Controls,
} from '@xyflow/react';
import './index.css';
 
import ResizableNode from './ResizableNode';
import ResizableNodeSelected from './ResizableNodeSelected';
import CustomResizerNode from './CustomResizerNode';
 
 
const nodeTypes = {
  ResizableNode,
  ResizableNodeSelected,
  CustomResizerNode,
};
 
const initialNodes = [
  {
    id: '1',
    type: 'ResizableNode',
    data: { label: 'NodeResizer' },
    position: { x: 0, y: 50 },
  },
  {
    id: '2',
    type: 'ResizableNodeSelected',
    data: { label: 'NodeResizer when selected' },
    position: { x: -100, y: 150 },
  },
  {
    id: '3',
    type: 'CustomResizerNode',
    data: { label: 'Custom Resize Icon' },
    position: { x: 150, y: 150 },
    style: {
      height: 100,
    },
  },
];
 
const initialEdges = [];
 
export default function NodeToolbarExample() {
  return (
    <ReactFlow
      defaultNodes={initialNodes}
      defaultEdges={initialEdges}
      minZoom={0.2}
      maxZoom={4}
      fitView
      nodeTypes={nodeTypes}
      fitViewOptions={{ padding: 0.5 }}
      colorMode="system"
    >
      <Background variant={BackgroundVariant.Dots} />
      <Controls />
    </ReactFlow>
  );
}
CustomResizerNode.jsx
import { memo } from 'react';
import { Handle, Position, NodeResizeControl } from '@xyflow/react';
 
const controlStyle = {
  background: 'transparent',
  border: 'none',
};
 
const CustomNode = ({ data }) => {
  return (
    <>
      <NodeResizeControl style={controlStyle} minWidth={100} minHeight={50}>
        <ResizeIcon />
      </NodeResizeControl>
 
      <Handle type="target" position={Position.Left} />
      <div>{data.label}</div>
      <Handle type="source" position={Position.Right} />
    </>
  );
};
 
function ResizeIcon() {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="20"
      height="20"
      viewBox="0 0 24 24"
      strokeWidth="2"
      stroke="#ff0071"
      fill="none"
      strokeLinecap="round"
      strokeLinejoin="round"
      style={{ position: 'absolute', right: 5, bottom: 5 }}
    >
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <polyline points="16 20 20 20 20 16" />
      <line x1="14" y1="14" x2="20" y2="20" />
      <polyline points="8 4 4 4 4 8" />
      <line x1="4" y1="4" x2="10" y2="10" />
    </svg>
  );
}
 
export default memo(CustomNode);
ResizableNode.jsx
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);
ResizableNodeSelected.jsx
import { memo } from 'react';
import { Handle, Position, NodeResizer } from '@xyflow/react';
 
const ResizableNodeSelected = ({ data, selected }) => {
  return (
    <>
      <NodeResizer
        color="#ff0071"
        isVisible={selected}
        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(ResizableNodeSelected);
index.css
@import url('@xyflow/react/dist/style.css');
/* we put the theme css at the end to override some of the default css variables and styles */
@import url('./xy-theme.css');
 
html,
body {
  margin: 0;
  font-family: sans-serif;
  box-sizing: border-box;
}
 
#app {
  width: 100vw;
  height: 100vh;
}
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.