Skip to Content
LearnCustomizationNodes

Nodes

A powerful feature of React Flow is the ability to create custom nodes. This gives you the flexibility to render anything you want within your nodes. We generally recommend creating your own custom nodes rather than relying on built-in ones. With custom nodes, you can add as many source and target handles as you like—or even embed form inputs, charts, and other interactive elements.

In this section, we’ll walk through creating a custom node featuring an input field that updates text elsewhere in your application. For further examples, we recommend checking out our Custom Node Example.

Implementing a Custom Node

To create a custom node, all you need to do is create a React component. React Flow will automatically wrap it in an interactive container that injects essential props like the node’s id, position, and data, and provides functionality for selection, dragging, and connecting handles. For a full reference on all available custom node props, see the Custom Node Props.

Let’s dive into an example by creating a custom node called TextUpdaterNode. For this, we’ve added a simple input field with a change handler. React Flow has a few handy pre-built components to simplify the process of creating custom nodes. We will use the Handle component to allow our custom node to connect with other nodes.

function TextUpdaterNode(props) { const onChange = useCallback((evt) => { console.log(evt.target.value); }, []); return ( <div className="text-updater-node"> <div> <label htmlFor="text">Text:</label> <input id="text" name="text" onChange={onChange} className="nodrag" /> </div> </div> ); }

Adding the Node Type

You can add a new node type to React Flow by adding it to the nodeTypes prop like below. We define the nodeTypes outside of the component to prevent re-renderings.

const nodeTypes = { textUpdater: TextUpdaterNode }; function Flow() { ... return ( <ReactFlow nodes={nodes} edges={edges} nodeTypes={nodeTypes} ... /> ); }

If nodeTypes are defined inside a component, they must be memoized. Otherwise, React creates a new object on every render, which leads to performance issues and bugs. Here’s how you can memoize the nodeTypes object inside a component using the useMemo hook:

const nodeTypes = useMemo(() => ({ textUpdater: TextUpdaterNode }), []); return <ReactFlow nodeTypes={nodeTypes} />;

After defining your new node type, you can use it by specifying the type property on your node definition:

const nodes = [ { id: 'node-1', type: 'textUpdater', position: { x: 0, y: 0 }, data: { value: 123 }, }, ];

After putting all together and adding some basic styles we get a custom node that prints text to the console:

import { useState } from 'react'; import { ReactFlow } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; import TextUpdaterNode from './TextUpdaterNode'; const rfStyle = { backgroundColor: '#B8CEFF', }; const initialNodes = [ { id: 'node-1', type: 'textUpdater', position: { x: 0, y: 0 }, data: { value: 123 }, }, ]; // we define the nodeTypes outside of the component to prevent re-renderings // you could also use useMemo inside the component const nodeTypes = { textUpdater: TextUpdaterNode }; function Flow() { const [nodes, setNodes] = useState(initialNodes); const [edges, setEdges] = useState([]); return ( <ReactFlow nodes={nodes} edges={edges} nodeTypes={nodeTypes} fitView style={rfStyle} /> ); } export default Flow;

To enable your custom node to connect with other nodes, check out the Handles page to learn how to add source and target handles.

Last updated on