Sankey / Flow Diagram

Pro

Flow diagram with reproducible column layout, cubic-bezier flow paths, width-proportional links and hover tooltip. Cyclic graphs are ranked rather than collapsed, and any flow it cannot draw is named under the diagram. Pure SVG.

</>sv-sankey-chart chartsankeyflow
import { SvSankeyChartComponent } from '@styloviz-pro/charts';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Sized canvas

Pro

Flow & node events

Pro

Heaviest node first

Pro

Validate a graph before it reaches the chart

Pro

When to use

  • Visualizing flow and proportion between stages: budgets, traffic, conversions, energy.
  • You want link widths proportional to magnitude.
  • The process loops — returns, refunds, recycled material. A backwards flow is drawn dashed and does not disturb the column order.
  • For simple stage counts, a funnel (Other Types) is lighter.

Async states

  • loading
  • empty
  • error
  • retry

Inputs

NameTypeDefaultDescription
loadingbooleanfalseTrue while the series is being fetched.
errorSvDataError | string | nullnullLoad failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`.
emptyMessagestring'No data to plot'Copy for the no-data state.
filteredbooleanfalseTrue when the emptiness is caused by a filter rather than an empty set.
nodesreadonly SankeyNode[][]Flow nodes: { id, label } (columns are auto-laid out).
linksreadonly SankeyLink[][]Flows between nodes: { source, target, value } (value sets link width).
nodeOrderSvSankeyNodeOrder'input'How nodes are stacked within a column. `'input'` follows the order of the `nodes` array, so reordering that array is how a host pins the layout. `'value'` puts the heaviest nodes at the top of each column. Both are reproducible: the same inputs always draw the same diagram.
variantSankeyVariant'default'Visual variant.
widthnumber540Diagram width in pixels.
heightnumber320Diagram height in pixels.
nodeWidthnumber18Node rectangle width in pixels.
nodePadnumber16Vertical padding between nodes in pixels.
titlestring''Chart title rendered above the diagram.
ariaLabelstring''Accessible name override for the diagram. Falls back to a generated summary.
customClassstring''Extra CSS classes applied to the root wrapper.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.
linkHoverSankeyLinkEventEmitted when a flow ribbon is hovered or keyboard-focused.
linkSelectSankeyLinkEventEmitted when a flow ribbon is clicked or activated via keyboard (Enter/Space).
nodeHoverSankeyNodeEventEmitted when a node is hovered or keyboard-focused.
nodeSelectSankeyNodeEventEmitted when a node is clicked or activated via keyboard (Enter/Space).

Wire it to your API

This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.

Template

Pro

Bound to the names this component actually exposes.

Host class

Pro

Drive the three async inputs from your own fetch.

  • This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `nodes`, `loading` and `error`.
  • Set `filtered` when a search or filter is active. It is the difference between "you have no orders" and "no orders match this filter" — telling a customer with 4,000 orders the first one reads as a bug.
  • Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.

Full walkthrough: Connecting to a backend.

Customization & theming

  • Reproducible column layout: longest-path ranking, with `nodeOrder` choosing input order or heaviest-first within a column.
  • Width-proportional links.
  • Per-node and per-link colors.
  • Backwards flows drawn dashed and excluded from ranking.

Best practices

  • Do: Keep node labels short; long names crowd the columns.
  • Do: Ensure inflow equals outflow per node so the diagram is honest.
  • Do: Order the `nodes` array the way you want each column stacked. That array is the layout control: `nodeOrder="input"` follows it exactly, and the order of `links` no longer affects the picture at all.
  • Don't: Send a negative value to mean a flow in the other direction. A ribbon has no direction but the one it is drawn in, so a negative magnitude is refused and reported rather than drawn as a thin positive flow. Reverse the source and target instead.
  • Tip: Color links by source or category to make paths traceable.
  • Tip: Read the note under the diagram during development. It names every flow that was refused — an unusable value, an unknown endpoint, a flow carrying nothing — which is usually a payload bug rather than a charting one.

Accessibility

  • The SVG is a `role="group"` with a generated summary (override via `ariaLabel`) — `group`, not `img`, because the ribbons and nodes are tab stops.
  • `sv-data-summary-table` publishes one row per flow, named "Source to Destination", with its value and its share of BOTH ends. Ribbon width is the value, and the two shares are what the picture makes obvious and a bare list of numbers does not: 60 out of a 600 source is a trickle, 60 into a 60 destination is everything that destination gets.
  • A backwards flow is marked "(backwards)" in its row and in its accessible name, not only by the dash. The dash is the one part of the drawing a screen reader cannot report and a colour-blind reader can miss.
  • The table lists what is actually on screen. A flow the chart refused is absent from it and named in the note instead, so the rows and the ribbons never disagree.
  • Ribbons and nodes are keyboard-focusable `role="button"` elements with `aria-label`s; hover/focus shows the tooltip and Enter/Space emits `linkSelect`/`nodeSelect`. Labels carry meaning beyond color.

Feedback on Sankey / Flow Diagram

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.