Dep Graph Viz

A dependency-graph layout primitive — circular nodes joined by directed arrows that point from dependency to dependent. Designed for spreadsheet recalc graphs, build pipelines, formula trees, and any narrative where "what depends on what" is the story.

DepGraphViz is a pure layout primitive. The component does not run the algorithm; it lays out the nodes and lights up whatever the caller passes via highlightedPath.

ABCDEF
Customize
Layout
16
60
50
Highlight

Installation

npx shadcn@latest add https://craftbits.dev/r/dep-graph-viz.json

Usage

import { DepGraphViz } from "@craft-bits/core";
 
const nodes = [
  { id: "A", label: "A" },
  { id: "B", label: "B" },
  { id: "D", label: "D" },
];
 
const edges = [
  { from: "A", to: "D" },
  { from: "B", to: "D" },
];
 
<DepGraphViz nodes={nodes} edges={edges} />;

Caller-driven coordinates — every node carries its own x and y, the component just draws:

<DepGraphViz
  nodes={[
    { id: "A", label: "A", x: 40, y: 40 },
    { id: "B", label: "B", x: 120, y: 40 },
    { id: "D", label: "D", x: 80, y: 120 },
  ]}
  edges={[
    { from: "A", to: "D" },
    { from: "B", to: "D" },
  ]}
/>;

Highlight a recalc order — nodes and the edges between consecutive pairs light up with the accent tone:

<DepGraphViz
  nodes={nodes}
  edges={edges}
  highlightedPath={["D", "E", "F"]}
/>;

Understanding the component

  1. Two layout modes. If every node carries explicit x and y, the component trusts the caller's coordinates — useful when the parent already has geometry (a spreadsheet grid, an AST, a hand-tuned scene). Otherwise it falls back to a longest-path topological auto-layout: each node sits one level below its deepest dependency, and within a level nodes are placed left-to-right in insertion order.
  2. Directed edges via arrowEndpoint. Edges are shortened to stop at the node boundary using the shared arrowEndpoint helper, so arrowheads never overlap node circles. Marker geometry is pulled from the shared SvgDefs block — the same arrows used in DAGRenderer and CycleRingViz.
  3. Highlighted path lights nodes and edges. Every id in highlightedPath becomes a "lit" node tinted with the accent. Consecutive pairs in the path also light up the edge between them (in either direction), so a recalc order, shortest-path trace, or topological traversal reads as a moving front.
  4. Token-driven styling. Node radius defaults to 16 px; lit fills resolve to var(--cb-accent-muted), lit strokes to var(--cb-accent), and rest fills to var(--cb-bg-elevated). Hex never leaks into the component body — themes drop in via CSS variables.
  5. Reduced motion. usePrefersReducedMotion() short-circuits node entry, edge draw, and stroke-colour transitions to instant. The graph snaps into place without any path-length animation.

Props

PropTypeDefaultDescription
nodesreadonly DepGraphNode[]requiredEach node has a stable id, a label, and optional x/y coordinates.
edgesreadonly DepGraphEdge[]requiredDirected edges with from (dependency) and to (dependent) node ids.
highlightedPathreadonly string[]Sequence of node ids — nodes and consecutive edges light up with the accent tone.
nodeRadiusnumber16Node circle radius in px.
hSpacingnumber60Horizontal spacing between auto-laid-out nodes.
vSpacingnumber50Vertical spacing between auto-laid-out levels.
classNamestringMerged onto the outer SVG element.

Accessibility

  • The outer SVG is role="img" with an aria-label summarising node and edge counts (for example, "Dependency graph: 6 nodes, 5 edges.").
  • Every node renders its label as a child text element, so identity is never communicated through colour alone.
  • Highlighted nodes and edges carry both a colour shift and a stroke-width bump, so emphasis survives high-contrast and grayscale rendering.
  • Motion respects prefers-reduced-motion: node entries, edge draws, and stroke-colour transitions all collapse to instant.

Credits

  • Extracted from: terminal-dreams (src/components/frontend-design/sdp-spreadsheet/ui/DepGraphViz.tsx). The original was scoped to the spreadsheet lab — it pulled depGraph, affectedCells, and recalcOrder from a custom useSpreadsheet context, hard-coded layout math against a single CSS-modules sheet, and rendered HTML chrome around the SVG. The library extract drops the lab chrome, generalises the API to flat nodes and edges lists, exposes caller-driven layout via optional x and y per node, generalises the affected-set into a highlightedPath sequence, switches to the shared SvgDefs arrow marker, and routes node and edge dimensions through SVG_TOKENS so it sits next to DAGRenderer and CycleRingViz without visual drift.