Skip to content
WANCRAFT

G.210Data & Feedback

Force Graph

A force-directed network graph in SVG: inline simulation that settles and stops, draggable nodes, zoom and pan, keyboard navigation.

NewReactSVGTailwindadvanced

Overview

Force Graph lays out a network with an inline simulation in the d3-force style — link springs, O(n²) many-body repulsion (fine up to 150 nodes), a gentle pull to the centre and collision — stepping at a fixed 60Hz and stopping once its energy (alpha) decays, so an idle graph costs nothing. The start is deterministic: nodes begin on a phyllotaxis spiral and are pre-settled during render, so the server markup hydrates as-is and the client only animates the final settle. Positions are written straight to the SVG while it moves and committed to React state when it rests. Drag a node and it pins to the pointer while the rest of the graph reacts; drag the background to pan, and zoom with the buttons, the + − 0 keys, Ctrl/⌘ + wheel or a pinch. Hover or focus a node to highlight its neighbourhood. Every node is a tab stop, arrow keys jump to the nearest node in that direction (connected nodes first), and a visually hidden adjacency list carries the structure.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/force-graph.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/force-graph.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/force-graph.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { ForceGraph, type ForceGraphData } from "@/components/ui/force-graph";

export function ForceGraphExample() {
  const data: ForceGraphData = {
    nodes: [
      { id: "ada", label: "Ada", group: "Design" },
      { id: "bao", label: "Bao", group: "Design" },
      { id: "jun", label: "Jun", group: "Engineering" },
      { id: "kai", label: "Kai", group: "Engineering" },
      { id: "lena", label: "Lena", group: "Engineering" },
      { id: "vik", label: "Vik", group: "Research" },
    ],
    links: [
      { source: "ada", target: "bao" },
      { source: "ada", target: "jun" },
      { source: "jun", target: "kai" },
      { source: "kai", target: "lena" },
      { source: "lena", target: "jun" },
      { source: "vik", target: "ada" },
    ],
  };

  return (
    <ForceGraph data={data} />
  );
}

03Props

PropTypeDefaultDescription
data{ nodes: { id; label; group? }[]; links: { source; target; value? }[] }—The network (required). Up to 150 nodes; duplicate, self and dangling links are ignored.
heightnumber440Graph height in px; the width follows the container (ResizeObserver).
linkDistancenumber48Resting length of the link springs in px. Changing it reheats the simulation.
chargenumber120Many-body repulsion strength. Changing it reheats the simulation.
labels"auto" | "all" | "none""auto"Auto labels hubs plus the highlighted neighbourhood; the highlighted node is always labelled.
accentstring"#FF7448"Colour of the first group and of highlighted links.
labelstring"Network graph"Accessible name of the graph.

04Features

  • 01Inline force simulation: springs, O(n²) repulsion, centring, collision, alpha decay
  • 02Deterministic pre-settled start (phyllotaxis seed) — SSR markup hydrates as-is
  • 03Fixed 60Hz steps; stops when settled, pauses offscreen and in hidden tabs
  • 04Drag nodes (pinned while held), pan the background, zoom by buttons, keys, Ctrl/⌘ + wheel or pinch
  • 05Hover or focus highlights a node's neighbours and links
  • 06Node size by degree, colour by group, labels for hubs
motion · continuousinput · draginput · hoverinput · focusinput · keyboardinput · pointer

05Accessibility

  • Every node is a focusable list item named with its label, group and number of connections; Tab moves through them.
  • Arrow keys move focus to the nearest node in that direction, preferring connected nodes; a focused node out of view is panned into view.
  • + and − zoom and 0 fits the graph while focus is inside it; the zoom buttons are labelled.
  • A visually hidden adjacency list states every node's connections.
  • Plain wheel scrolling is never captured (zoom needs Ctrl/⌘). With prefers-reduced-motion the layout settles instantly, unanimated.

06Limitations

  • Capped at 150 nodes (O(n²) forces); larger graphs need Barnes–Hut and canvas rendering.
  • Touch dragging inside the graph pans it instead of scrolling the page.