> ## Documentation Index
> Fetch the complete documentation index at: https://velt.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# React Flow Editor

> Setup Multiplayer Editing for React Flow diagrams.

The `@veltdev/reactflow-crdt` library enables real-time collaborative editing on React Flow diagrams. The collaboration editing engine is built on top of [Yjs](https://docs.yjs.dev/) and Velt SDK.

## Prerequisites

* Node.js (v14 or higher)
* React (v16.8 or higher for hooks)
* A Velt account with an API key ([sign up](https://console.velt.dev/))
* Optional: TypeScript for type safety

## Setup

### Step 1: Install Dependencies

Install the required packages:

```bash theme={null}
npm install @veltdev/reactflow-crdt @veltdev/react
```

### Step 2: Setup Velt

Initialize the Velt client by following the [Velt Setup Docs](https://velt.dev/docs/get-started/quickstart.md). This is required for the collaboration engine to work.

### Step 3: Initialize Velt CRDT Extension

* Initialize the Velt CRDT extension and use it to initialize the React Flow diagram.
* Pass an `editorId` to uniquely identify each diagram instance you have in your app. This is especially important when you have multiple diagrams in your app.

```jsx theme={null}
const { nodes, edges, onNodesChange, onEdgesChange, onConnect } = useVeltReactFlowCrdtExtension({
  editorId: 'YOUR_EDITOR_ID',
  initialNodes: [{ id: '1', data: { label: 'Start' }, position: { x: 0, y: 0 } }],
  initialEdges: []
});

return (
  <ReactFlow
    nodes={nodes}
    edges={edges}
    onNodesChange={onNodesChange}
    onEdgesChange={onEdgesChange}
    onConnect={onConnect}
    fitView
  >
    <Background />
  </ReactFlow>
);
```

## Notes

* **Unique editorId**: Use a unique `editorId` per diagram instance.
* **Use CRDT handlers**: Always apply the store-provided `nodes`, `edges`, `onNodesChange`, `onEdgesChange`, and `onConnect`.

## Testing and Debugging

**To test collaboration:**

1. Login two unique users on two browser profiles and open the same page in both.
2. Move nodes or create connections in one window and verify they sync in the other.

**Common issues:**

* Nodes/edges not syncing: Ensure each diagram has a unique `editorId` and the Velt client is initialized. Also ensure that you are logged in with two different users in two different browser profiles.
* No updates on connect: Use the provided CRDT-aware `nodes`, `edges`, `onNodesChange`/`onEdgesChange` and `onConnect` handlers from the store.

> [!TIP]
>
> Use the [VeltCrdtStoreMap debugging interface](https://velt.dev/docs/realtime-collaboration/crdt/setup/core.md#veltcrdtstoremap) to inspect and monitor your CRDT stores in real-time from the browser console.

## Complete Example

> [tab] React / Next.js
>
> [Open Live Demo In Larger Window](https://sample-apps-reactflow-demo.vercel.app/) | [View Demo Repo](https://github.com/velt-js/sample-apps/tree/main/apps/react/crdt/canvas/reactflow/reactflow-demo)
>
> ```jsx Complete Implementation expandable lines theme={null}
> import {
>     Background,
>     ReactFlow,
>     ReactFlowProvider,
>     useReactFlow,
>     type Edge
> } from '@xyflow/react';
> import { useCallback, useRef } from 'react';
> import { useVeltInitState } from '@veltdev/react';
> import { useVeltReactFlowCrdtExtension } from '@veltdev/reactflow-crdt';
> import '@xyflow/react/dist/style.css';
>
> const initialNodes = [
>     {
>         id: '0',
>         type: 'input',
>         data: { label: 'Node' },
>         position: { x: 0, y: 50 },
>     },
> ];
> const initialEdges: Edge[] = [];
>
> let id = 9;
> const getId = () => `${id++}`;
> const nodeOrigin: [number, number] = [0.5, 0];
>
> const AddNodeOnEdgeDrop = () => {
>     const { nodes, edges, onNodesChange, onEdgesChange, onConnect } = useVeltReactFlowCrdtExtension({
>         editorId: 'YOUR_EDITOR_ID',
>         initialEdges,
>         initialNodes,
>     });
>
>     const reactFlowWrapper = useRef(null);
>     const { screenToFlowPosition } = useReactFlow();
>
>     const onConnectEnd = useCallback(
>         (event: any, connectionState: any) => {
>             if (!connectionState.isValid) {
>                 const id = getId();
>                 const { clientX, clientY } = 'changedTouches' in event ? event.changedTouches[0] : event;
>                 const newNode = {
>                     id,
>                     position: screenToFlowPosition({ x: clientX, y: clientY }),
>                     data: { label: `Node ${id}` },
>                     origin: [0.5, 0.0],
>                 };
>
>                 // Add new node using CRDT-aware change handler
>                 onNodesChange([{ type: 'add', item: newNode }]);
>
>                 // Add new edge using CRDT-aware change handler
>                 const newEdge = {
>                     id,
>                     source: connectionState.fromNode.id,
>                     target: id,
>                 };
>                 onEdgesChange([{ type: 'add', item: newEdge }]);
>             }
>         },
>         [screenToFlowPosition, onNodesChange, onEdgesChange],
>     );
>
>     return (
>         <div className="react-flow-container" ref={reactFlowWrapper} >
>             <ReactFlow
>                 style={{ backgroundColor: "#F7F9FB" }}
>                 nodes={nodes}
>                 edges={edges}
>                 onNodesChange={onNodesChange}  // CRDT-synced node changes
>                 onEdgesChange={onEdgesChange}  // CRDT-synced edge changes
>                 onConnect={onConnect}  // CRDT-synced connections
>                 onConnectEnd={onConnectEnd}  // Custom handler for adding nodes/edges
>                 fitView
>                 fitViewOptions={{ padding: 2 }
>                 }
>                 nodeOrigin={nodeOrigin}
>             >
>                 <Background />
>             </ReactFlow>
>         </div>
>     );
> };
>
> function ReactFlowComponent() {
>     const veltInitialized = useVeltInitState();
>
>     if (!veltInitialized) {
>         return <div>Loading...</div>;
>     }
>
>     return (
>         <ReactFlowProvider>
>             <AddNodeOnEdgeDrop />
>         </ReactFlowProvider>
>     );
> }
>
> export default ReactFlowComponent;
> ```

> [tab] Live Demo
>
> [Open Live Demo In Larger Window](https://sample-apps-reactflow-demo.vercel.app/) | [View Demo Repo](https://github.com/velt-js/sample-apps/tree/main/apps/react/crdt/canvas/reactflow/reactflow-demo)
>
> [https://sample-apps-reactflow-demo.vercel.app/](https://sample-apps-reactflow-demo.vercel.app/)

## APIs

### Custom Encryption

You can encrypt CRDT data before it’s stored in Velt by registering a custom encryption provider. For CRDT methods, input data is of type `Uint8Array | number[]`.

> [tab] React / Next.js
>
> ```ts theme={null}
> async function encryptData(config: EncryptConfig<number[]>): Promise<string> {
>   const encryptedData = await yourEncryptDataMethod(config.data);
>   return encryptedData;
> }
>
> async function decryptData(config: DecryptConfig<string>): Promise<number[]> {
>   const decryptedData = await yourDecryptDataMethod(config.data);
>   return decryptedData;
> }
>
> const encryptionProvider: VeltEncryptionProvider<number[], string> = {
>   encrypt: encryptData,
>   decrypt: decryptData,
> };
>
> <VeltProvider
>   apiKey="YOUR_API_KEY"
>   encryptionProvider={encryptionProvider}
> />
>
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> async function encryptData(config: EncryptConfig<number[]>): Promise<string> {
>   const encryptedData = await yourEncryptDataMethod(config.data);
>   return encryptedData;
> }
>
> async function decryptData(config: DecryptConfig<string>): Promise<number[]> {
>   const decryptedData = await yourDecryptDataMethod(config.data);
>   return decryptedData;
> }
>
> const encryptionProvider: VeltEncryptionProvider<number[], string> = {
>   encrypt: encryptData,
>   decrypt: decryptData,
> };
>
> client.setEncryptionProvider(encryptionProvider);
> ```

See also: [setEncryptionProvider()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#setencryptionprovider-encryptionprovider)
· [VeltEncryptionProvider](https://velt.dev/docs/api-reference/sdk/models/data-models.md#veltencryptionprovider)
· [EncryptConfig](https://velt.dev/docs/api-reference/sdk/models/data-models.md#encryptconfig)
· [DecryptConfig](https://velt.dev/docs/api-reference/sdk/models/data-models.md#decryptconfig)

### [useVeltReactFlowCrdtExtension()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#useveltreactflowcrdtextension)

Provides real-time collaborative editing on React Flow diagrams with Yjs and Velt SDK.

* Signature: `useVeltReactFlowCrdtExtension(config: VeltReactFlowCrdtExtensionConfig)`
* Params: [VeltReactFlowCrdtExtensionConfig](https://velt.dev/docs/api-reference/sdk/models/data-models.md#veltreactflowcrdtextensionconfig)
  * `editorId`: Unique identifier for the diagram instance.
  * `initialNodes`: Initial set of nodes.
  * `initialEdges`: Initial set of edges.
  * `debounceMs`: Debounce time for update propagation (ms).
* Returns: [VeltReactFlowCrdtExtensionResponse](https://velt.dev/docs/api-reference/sdk/models/data-models.md#veltreactflowcrdtextensionresponse)
  * `store`: React Flow CRDT store instance.
  * `nodes`: Array of nodes in the diagram.
  * `edges`: Array of edges in the diagram.
  * `onNodesChange`: CRDT-aware handler to apply node changes.
  * `onEdgesChange`: CRDT-aware handler to apply edge changes.
  * `onConnect`: CRDT-aware handler to apply connect changes.
  * `setNodes`: Method to set nodes
  * `setEdges`: Method to set edges

### [onNodesChange()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#onnodeschange)

CRDT-aware handler to apply node changes (add/update/remove) that sync across collaborators.

* Params: [NodeChange\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#nodechange)
* Returns: `void`

```tsx theme={null}
onNodesChange([{ type: 'add', item: newNode }]);
```

### [onEdgesChange()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#onedgeschange)

CRDT-aware handler to apply edge changes (add/update/remove) that sync across collaborators.

* Params: [EdgeChange\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#edgechange)
* Returns: `void`

```tsx theme={null}
onEdgesChange([{ type: 'add', item: newEdge }]);
```

### [onConnect()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#onconnect)

CRDT-aware connect handler compatible with React Flow’s `<ReactFlow onConnect={...} />`.

* Params: [Connection](https://velt.dev/docs/api-reference/sdk/models/data-models.md#connection)
* Returns: `void`

```tsx theme={null}
<ReactFlow onConnect={onConnect} />
```

### [setNodes()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#setnodes)

Imperative setter for nodes (useful for non-event updates). Synced via the store.

* Params: [Node\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#node-react-flow)
* Returns: `void`

```tsx theme={null}
setNodes(prev => [...prev, myNode]);
```

### [setEdges()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#setedges)

Imperative setter for edges (useful for non-event updates). Synced via the store.

* Params: [Edge\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#edge-react-flow)
* Returns: `void`

```tsx theme={null}
setEdges(prev => [...prev, myEdge]);
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.