Your First Graph
This tutorial takes you all the way from a blank HTML page to a styled, force-laid-out graph that responds to clicks and grows when you add a node at runtime. Follow the numbered steps in order; each one adds a little to the same script, and the full combined version is at the end.
It assumes you’ve already installed @kortexya/nodus.
1. Create the container
Nodus renders into a DOM element that has a real size. Add one to your page, and give it width and height with CSS so the renderer has somewhere to draw.
<div id="graph"></div>
<style> html, body { margin: 0; height: 100%; } #graph { width: 100vw; height: 100vh; }</style>You only need this HTML and CSS once. Everything else in the tutorial is
JavaScript that runs against the #graph element.
2. Create the Nodus instance
Import Nodus and construct it with the container. The WebAssembly core
auto-initializes on import, so there’s no async
setup step — new Nodus(...) is synchronous and ready to use immediately.
import { Nodus } from '@kortexya/nodus';
const nodus = new Nodus({ container: document.getElementById('graph') });You can also pass the element’s id as a string instead of the element itself.
3. Load a small graph
A graph is plain JSON: a list of nodes and a list of edges. Each node has an
id; each edge references nodes by source and target. Put your own payload
under data — it’s typed and read back later with node.getData().
await nodus.setGraph({ nodes: [ { id: 'alice', data: { name: 'Alice', role: 'author' } }, { id: 'bob', data: { name: 'Bob', role: 'author' } }, { id: 'carol', data: { name: 'Carol', role: 'editor' } }, { id: 'dave', data: { name: 'Dave', role: 'author' } }, ], edges: [ { source: 'alice', target: 'bob' }, { source: 'bob', target: 'carol' }, { source: 'carol', target: 'dave' }, { source: 'dave', target: 'alice' }, ],});setGraph replaces the entire graph. At this point the nodes exist but have no
positions and no styling yet.
4. Add node and edge style rules
Rather than styling each element by hand, add style rules.
A rule applies to every matching element, and the values it sets are
visual attributes such as color, radius,
shape and text. Attribute values can also be functions of the element, which
is how the label below reads each node’s own data.
// Every node: a teal circle with its name as a label underneath.nodus.styles.addNodeRule({ color: '#0f766e', radius: 18, shape: 'circle', text: { content: (node) => node.getData().name, position: 'bottom', },});
// Every edge: a thin grey line with an arrowhead at the target end.nodus.styles.addEdgeRule({ color: '#94a3b8', width: 2, shape: { head: 'arrow' },});color is a CSS color string, radius controls node size, and an edge’s
shape.head of 'arrow' draws an arrowhead pointing at the target node.
5. Run a force layout
A fresh graph has no coordinates, so nothing is arranged yet. Apply the force
layout to spread the nodes out. Layouts are async and return a Promise. The
duration option (in milliseconds) animates the transition — use a positive
value to watch the nodes settle, or duration: 0 to jump straight to the final
positions.
await nodus.layouts.force({ duration: 800 });See Applying Layouts for the other layouts (force-link, hierarchical, radial, concentric, grid and sequential).
6. Frame the graph
After layout the graph may sit anywhere relative to the viewport.
view.locateGraph() pans and zooms the camera
so the whole graph fits neatly on screen. It’s async, so await it.
await nodus.view.locateGraph();7. React to clicks with a tooltip handler
Register pointer handlers through the tooltip tool.
onNodeClick fires with the clicked Node, and you can read its data or show
a tooltip with the tool’s own show method.
nodus.tools.tooltip.onNodeClick((node) => { const { name, role } = node.getData(); nodus.tools.tooltip.show(`${name} — ${role}`);});Call nodus.tools.tooltip.hide() whenever you want to dismiss the tooltip.
8. Add a node at runtime and re-layout
Graphs aren’t static. addNode inserts a new node and returns the created
Node; addEdge connects it. After changing the structure, run the layout
again so the new element finds a sensible position, then re-frame the view.
async function addCollaborator() { nodus.addNode({ id: 'erin', data: { name: 'Erin', role: 'author' } }); nodus.addEdge({ source: 'erin', target: 'alice' });
await nodus.layouts.force({ duration: 600 }); await nodus.view.locateGraph();}
// e.g. wire this to a button in your page:// document.getElementById('add').addEventListener('click', addCollaborator);The new node automatically picks up the style rules you added in step 4 — rules apply to every matching element, including ones added later.
9. The full script
Here is everything from steps 2–8 combined into one runnable module. Pair it with the container HTML and CSS from step 1.
import { Nodus } from '@kortexya/nodus';
// 2. Create the instance.const nodus = new Nodus({ container: document.getElementById('graph') });
// 3. Load a small graph.await nodus.setGraph({ nodes: [ { id: 'alice', data: { name: 'Alice', role: 'author' } }, { id: 'bob', data: { name: 'Bob', role: 'author' } }, { id: 'carol', data: { name: 'Carol', role: 'editor' } }, { id: 'dave', data: { name: 'Dave', role: 'author' } }, ], edges: [ { source: 'alice', target: 'bob' }, { source: 'bob', target: 'carol' }, { source: 'carol', target: 'dave' }, { source: 'dave', target: 'alice' }, ],});
// 4. Style nodes and edges.nodus.styles.addNodeRule({ color: '#0f766e', radius: 18, shape: 'circle', text: { content: (node) => node.getData().name, position: 'bottom' },});nodus.styles.addEdgeRule({ color: '#94a3b8', width: 2, shape: { head: 'arrow' },});
// 5–6. Lay it out and frame it.await nodus.layouts.force({ duration: 800 });await nodus.view.locateGraph();
// 7. React to clicks.nodus.tools.tooltip.onNodeClick((node) => { const { name, role } = node.getData(); nodus.tools.tooltip.show(`${name} — ${role}`);});
// 8. Grow the graph at runtime.async function addCollaborator() { nodus.addNode({ id: 'erin', data: { name: 'Erin', role: 'author' } }); nodus.addEdge({ source: 'erin', target: 'alice' }); await nodus.layouts.force({ duration: 600 }); await nodus.view.locateGraph();}You now have a complete, styled, interactive graph that lays itself out, reacts to clicks and grows on demand.
Next steps
- An Interactive Explorer — hover highlights, selection, search and neighbor expansion on a larger graph.
- Building a Graph — add, update and remove elements.
- Styling Nodes & Edges — the full visual model.
- Applying Layouts — every layout and its options.
- Handling Events — graph-lifecycle events.