Skip to content
D
Documentation

React quick start

tutorial
2 min readUpdated

Mount a controlled canvas with two connected nodes, and keep its instance in a ref for a Fit view button.

Framework bindings are thin skins over one headless model: specs describe your intent, live models hold the data, and the engine owns behavior.

Prerequisites

Use a browser-based React project with TypeScript and JSX configured, React and React DOM 17, 18 or 19 (18 or 19 for the mounting code below), and the binding's @grafloria/element ^0.5.0 peer; see JavaScript quick start for the shared engine and renderer prerequisites.

1. Install the binding and its peers

Run this in your application's directory:

bash
npm install @grafloria/react @grafloria/engine @grafloria/renderer @grafloria/element react react-dom

2. Create the controlled canvas

Render GrafloriaFlow with typed NodeSpec and EdgeSpec data. The edge's source and target identify the two nodes.

useNodesState and useEdgesState each return a three-element tuple: the specs, a state setter and a canvas change handler. Pass the third element to the corresponding change prop to mirror canvas edits into React state.

Store the DiagramInstance received by onInit in a React ref. The button calls fitView() on that mounted instance to frame the content; the fitView prop also frames it at startup. plugins adds the shipped minimap, zoom/fit controls and background grid.

tsx
import { useRef } from 'react';
import {
  GrafloriaFlow,
  useNodesState,
  useEdgesState,
} from '@grafloria/react';
import type {
  DiagramInstance,
  NodeSpec,
  EdgeSpec,
} from '@grafloria/react';

const initialNodes: NodeSpec[] = [
  {
    id: 'a',
    position: { x: 60, y: 80 },
    size: { width: 180, height: 80 },
    data: { label: 'Ingest' },
  },
  {
    id: 'b',
    position: { x: 380, y: 80 },
    size: { width: 180, height: 80 },
    data: { label: 'Publish' },
  },
];

const initialEdges: EdgeSpec[] = [
  { id: 'e1', source: 'a', target: 'b' },
];

export default function App() {
  const instanceRef = useRef<DiagramInstance | null>(null);
  const [nodes, , onNodesChange] = useNodesState(initialNodes);
  const [edges, , onEdgesChange] = useEdgesState(initialEdges);

  return (
    <main>
      <button
        type="button"
        onClick={() => instanceRef.current?.fitView()}
      >
        Fit view
      </button>
      <div style={{ width: '100%', height: 400 }}>
        <GrafloriaFlow
          nodes={nodes}
          edges={edges}
          onNodesChange={onNodesChange}
          onEdgesChange={onEdgesChange}
          onInit={(instance) => { instanceRef.current = instance; }}
          fitView
          plugins
        />
      </div>
    </main>
  );
}
Ingest connects to Publish across the dotted canvas. Look for the Fit view button above it, zoom/fit controls at the lower left and the minimap at the lower right.

The canvas occupies the 400-pixel-high wrapper. For other sizing arrangements, see Theme a canvas.

Keep the controlled return path wired

Passing controlled nodes without onNodesChange lets stale React state overwrite user edits. Pass the hook's third element, not its setNodes setter: the callback receives live NodeModel objects, while the setter accepts NodeSpec[] or a state updater. The hook converts those live models back to specs. The second tuple element is omitted in this sample because it does not make application-originated edits.

onInit runs after the instance is created. The binding disposes that instance when the flow unmounts; do not dispose it after initialization.

3. Mount the app

For a React 18 or 19 client entry, render App into your HTML root element:

tsx
import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('root');
if (!container) throw new Error('Missing #root element');

createRoot(container).render(<App />);

Use the HTML entry structure from JavaScript quick start, replacing its editor markup and script with the React root and TSX entry:

html
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>

This HTML entry fits a Vite React TypeScript project. If your framework already mounts App, keep its entry point instead.

Start your application's development server and open it in the browser. You now have Ingest and Publish nodes joined by an edge, with a Fit view button above the canvas. Drag a node to move it; the change handler mirrors the edit into React state. Pan or zoom, then click Fit view to frame both nodes again.

Where next

Was this page helpful?