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.
Customize
Layout
16
60
50
Highlight
Installation
npx shadcn@latest add https://craftbits.dev/r/dep-graph-viz.jsonUsage
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
- Two layout modes. If every node carries explicit
xandy, 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. - Directed edges via
arrowEndpoint. Edges are shortened to stop at the node boundary using the sharedarrowEndpointhelper, so arrowheads never overlap node circles. Marker geometry is pulled from the sharedSvgDefsblock — the same arrows used inDAGRendererandCycleRingViz. - Highlighted path lights nodes and edges. Every id in
highlightedPathbecomes 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. - Token-driven styling. Node radius defaults to 16 px; lit fills resolve to
var(--cb-accent-muted), lit strokes tovar(--cb-accent), and rest fills tovar(--cb-bg-elevated). Hex never leaks into the component body — themes drop in via CSS variables. - 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
| Prop | Type | Default | Description |
|---|---|---|---|
nodes | readonly DepGraphNode[] | required | Each node has a stable id, a label, and optional x/y coordinates. |
edges | readonly DepGraphEdge[] | required | Directed edges with from (dependency) and to (dependent) node ids. |
highlightedPath | readonly string[] | — | Sequence of node ids — nodes and consecutive edges light up with the accent tone. |
nodeRadius | number | 16 | Node circle radius in px. |
hSpacing | number | 60 | Horizontal spacing between auto-laid-out nodes. |
vSpacing | number | 50 | Vertical spacing between auto-laid-out levels. |
className | string | — | Merged onto the outer SVG element. |
Accessibility
- The outer SVG is
role="img"with anaria-labelsummarising 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 pulleddepGraph,affectedCells, andrecalcOrderfrom a customuseSpreadsheetcontext, 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 flatnodesandedgeslists, exposes caller-driven layout via optionalxandyper node, generalises the affected-set into ahighlightedPathsequence, switches to the sharedSvgDefsarrow marker, and routes node and edge dimensions throughSVG_TOKENSso it sits next toDAGRendererandCycleRingVizwithout visual drift.