Sankey

Weighted-flow diagram. Nodes arranged in horizontal columns by topological depth; link thickness encodes flow value. Use for funnels, energy/material/money flows, and any "value moving from A to B" picture.

Installation

pnpm
pnpm dlx @hex-core/cli add sankey

Usage

tsx
import { Sankey } from "@/components/ui/sankey"

Energy flow

Two sources flowing into a single sink.

tsx
<Sankey
  nodes={[
    { id: "coal", label: "Coal" },
    { id: "gas", label: "Gas" },
    { id: "grid", label: "Grid" },
  ]}
  links={[
    { source: "coal", target: "grid", value: 60 },
    { source: "gas", target: "grid", value: 30 },
  ]}
/>

Funnel-style with hover

Surface link details on hover for tooltips.

tsx
<Sankey
  nodes={steps}
  links={transitions}
  onLinkHover={(l) => setActive(l)}
/>

API Reference

PropTypeDefaultDescription
nodesrequired
objectArray of { id, label }. Every link's source/target MUST match an id here.
linksrequired
objectArray of { source, target, value }. Values must be positive.
width
number720SVG pixel width.
height
number420SVG pixel height.
nodeAlign
"left" | "right" | "center" | "justify"justifyColumn alignment strategy.
nodeWidth
number12Pixel width of each node rectangle.
nodePadding
number8Vertical pixel gap between nodes in the same column.
onLinkHover
functionCalled with the hovered SankeyLink (or null when hover ends).
onNodeClick
functionCalled with the clicked SankeyNode.
className
stringAdditional CSS classes on the SVG element.

AI Guidance

When to use

Visualize how a quantity is distributed and re-distributed across a multi-step pipeline — energy mix, marketing-funnel transitions, traffic referral flows, budget allocation by department × line-item. The thicker the link, the more value moves along it.

When not to use

Don't use for hierarchies (use TreeMap or Sunburst). Don't use for arbitrary node-edge graphs without a clear left-to-right flow (use Canvas). Don't use when total flow doesn't conserve from column to column — d3-sankey assumes a balanced graph.

Common mistakes

  • A link's source or target id not present in `nodes` — d3-sankey throws an opaque error. Validate ids upstream
  • Negative or zero `value` — produces zero-width or NaN-positioned links. Filter or clamp upstream
  • Cycles in the link graph — d3-sankey requires a DAG. If your data has feedback loops, collapse them or split into multiple Sankeys
  • Mutating the input `nodes` / `links` between renders — the component clones internally to protect consumer arrays, but unmemoized inputs still trigger a full re-layout each render. Memoize

Accessibility

The SVG carries role="img" with a <title> and <desc> summarizing node and link counts. For agent outputs, also expose a parallel <table> of source / target / value triples so screen-reader users get the flow magnitudes.

Token budget: 360

Verified against @hex-core/components@1.12.0