Skip to main content

graph

The only required prop. It describes your network as two arrays:

type GraphData = {
nodes: Array<{ id: string | number } & YourNodeData>;
links: Array<{ source: number; target: number } & YourLinkData>;
};
const data = {
nodes: [{ id: "a" }, { id: "b" }, { id: "c" }],
links: [
{ source: 0, target: 1 }, // a — b
{ source: 1, target: 2 }, // b — c
],
};

<Graph graph={data} chargeForce={{ strength: -200 }} />;
<Graph graph={{ nodes, links }} />Live

Nodes

Every node needs an id (string or number). Beyond that, attach whatever data your NodeComponent needs — names, images, colors, whole objects:

const nodes = [
{ id: 1, name: "Michael Scott", title: "Regional Manager", avatar: "/img/michael.png" },
{ id: 2, name: "Dwight Schrute", title: "Assistant to the Regional Manager" },
];
source and target are array indices

source: 0, target: 1 connects nodes[0] to nodes[1] — the positions in the array, not the id values. This is the most common source of confusion when wiring up real data.

Like nodes, links accept extra fields, which your LinkComponent receives — useful for styling by relationship type:

const links = [
{ source: 0, target: 1, kind: "reports-to" },
{ source: 0, target: 2, kind: "mentors" },
];

Linking by id

If your data references nodes by id (as most APIs do), convert it once before rendering:

const byId = new Map(rawNodes.map((node, index) => [node.id, index]));

const links = rawLinks.map((link) => ({
...link,
source: byId.get(link.source),
target: byId.get(link.target),
}));

Updating the data

The simulation is rebuilt when the graph object changes, so treat it immutably — create a new object instead of mutating the arrays in place:

const [data, setData] = useState(initialData);

const addNode = (node) =>
setData((prev) => ({
nodes: [...prev.nodes, node],
links: [...prev.links, { source: 0, target: prev.nodes.length }],
}));