Skip to content
WANCRAFT

G.208Data & Feedback

Sankey Diagram

A Sankey flow diagram with an inline layout: hover or focus a node to trace its flows, keyboard navigation and animated data changes.

NewReactMotionSVGTailwindadvanced

Overview

Sankey Diagram draws how quantities flow between stages, with its layout implemented inline (no d3): links that would close a cycle are set aside, nodes go into columns by their longest path from a source, values are scaled so the fullest column fits, and node positions are relaxed over 32 passes toward the value-weighted centre of their neighbours, resolving overlaps after each column. Links are cubic Béziers whose width is their value, stacked at each node in the order of their other end to minimise crossings, and coloured by a source-to-target gradient, either end or neutral ink. Hover, tap or focus a node to light up everything flowing into and out of it, or hover a link for its value and share. Every node is a tab stop; arrow keys move within a column and follow the largest flow across columns. When the data changes, nodes and links spring to their new places while new ones fade in. A visually hidden table lists every link.

01Installation

Method 01 · Registry

CLI verified

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

npx shadcn@latest add https://wancraft.my/r/sankey-diagram.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/sankey-diagram.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
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 { SankeyDiagram, type SankeyData } from "@/components/ui/sankey-diagram";

export function SankeyDiagramExample() {
  const data: SankeyData = {
    nodes: [
      { id: "search", label: "Search" },
      { id: "social", label: "Social" },
      { id: "docs", label: "Docs" },
      { id: "pricing", label: "Pricing" },
      { id: "signup", label: "Sign-up" },
      { id: "bounce", label: "Bounce" },
    ],
    links: [
      { source: "search", target: "docs", value: 620 },
      { source: "search", target: "pricing", value: 240 },
      { source: "social", target: "docs", value: 180 },
      { source: "social", target: "pricing", value: 150 },
      { source: "docs", target: "signup", value: 310 },
      { source: "docs", target: "bounce", value: 490 },
      { source: "pricing", target: "signup", value: 260 },
      { source: "pricing", target: "bounce", value: 130 },
    ],
  };

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

03Props

PropTypeDefaultDescription
data{ nodes: { id; label; color? }[]; links: { source; target; value }[] }—Nodes and links (required). Links that would close a cycle, and nodes with no links, are left out.
heightnumber380Diagram height in px; the width follows the container (ResizeObserver).
nodeWidthnumber12Width of each node bar in px.
nodePaddingnumber14Vertical gap between nodes in px (shrinks automatically in crowded columns).
linkColor"gradient" | "source" | "target" | "neutral""gradient"Link colouring.
align"justify" | "left""justify"Justify pushes nodes without outgoing links to the last column; left keeps them at their depth.
showValuesbooleantrueShow each node's value beside its label (hidden below 480px wide; values stay in the tooltip and accessible names).
accentstring"#FF7448"Colour of the first node; others use a categorical palette unless they set color.
format(value: number) => string—Value formatter (compact en-US by default).
labelstring"Flow diagram"Accessible name of the diagram and caption of the hidden link table.

04Features

  • 01Inline layout: cycle-safe columns by depth, 32 relaxation passes, value-scaled bands
  • 02Cubic Bézier links stacked in the order of their other end to reduce crossings
  • 03Gradient, source, target or neutral link colours
  • 04Hover, tap or focus a node to trace all upstream and downstream flow; hover a link for its value and share
  • 05Data changes spring nodes and links to their new places; new ones fade in, removed ones fade out
  • 06Responsive width via ResizeObserver (resizes don't animate)
motion · springmotion · layoutinput · hoverinput · focusinput · keyboardinput · click

05Accessibility

  • Every node is a focusable list item with a name stating its value, inflow, outflow and share of the total; Tab moves through them in column order.
  • Arrow Up/Down move within a column; Arrow Left/Right follow the largest flow into the previous or next column; Home and End jump to the first and last node.
  • Escape hides the details tooltip without moving focus (and only acts while it is shown).
  • A visually hidden table lists every link as source, target and value.
  • Visible focus ring on nodes; with prefers-reduced-motion data changes apply instantly.

06Limitations

  • Links that would form a cycle are dropped from the drawing and the table.
  • Very small nodes keep a 1px minimum height; labels may overlap links in narrow containers.