Node and Link Ordering
By default ApexSankey computes node positions automatically to minimize edge crossings. When you need a specific vertical order, for example to keep a consistent narrative from top to bottom, supply an explicit order array in the data's options field.
The order array
order is a three-level nested array passed inside data.options:
- The outer array is one entry per column (rank), left to right.
- Each column contains one or more groups.
- Each group is an array of node IDs, listed top to bottom.
const data = {
nodes: [
{ id: 'LinkedIn', title: 'LinkedIn' },
{ id: 'Indeed', title: 'Indeed' },
{ id: 'Referral', title: 'Referral' },
{ id: 'Applied', title: 'Applied' },
{ id: 'Responded', title: 'Responded' },
{ id: 'No Response', title: 'No Response' },
{ id: 'Interviewed', title: 'Interviewed' },
{ id: 'Rejected', title: 'Rejected' },
{ id: 'Accepted', title: 'Accepted' },
],
edges: [
{ source: 'LinkedIn', target: 'Applied', value: 85, type: 'src' },
{ source: 'Indeed', target: 'Applied', value: 62, type: 'src' },
{ source: 'Referral', target: 'Applied', value: 28, type: 'src' },
{ source: 'Applied', target: 'Responded', value: 70, type: 'stage' },
{ source: 'Applied', target: 'No Response', value: 105, type: 'stage' },
{ source: 'Responded', target: 'Interviewed', value: 22, type: 'stage' },
{ source: 'Responded', target: 'Rejected', value: 48, type: 'stage' },
{ source: 'Interviewed', target: 'Accepted', value: 22, type: 'stage' },
],
options: {
order: [
[['LinkedIn', 'Indeed', 'Referral']], // column 0: three source nodes
[['Applied']], // column 1
[['Responded'], ['No Response']], // column 2: two groups
[['Interviewed'], ['Rejected']], // column 3
[['Accepted']], // column 4
],
},
}
const sankey = new ApexSankey(document.getElementById('chart'), {})
sankey.render(data)
How columns map to ranks
Each top-level entry corresponds to a column in the diagram. The first entry is the leftmost column; the last is the rightmost. Every node must appear exactly once across the array, in the column that matches its position in the flow.
options: {
order: [
// column 0 (sources)
[['A', 'B', 'C']],
// column 1 (middle)
[['D']],
// column 2 (targets)
[['E', 'F']],
],
}
Grouping within a column
Within a column, splitting nodes into separate groups (separate inner arrays) lets you cluster related nodes and control spacing between clusters. A single group keeps nodes tightly ordered; multiple groups introduce visual separation:
options: {
order: [
[['source1', 'source2']],
// two distinct groups in this column — rendered with a visual gap
[
['success_path_a', 'success_path_b'],
['failure_path'],
],
],
}
When to use explicit ordering
- Funnels and pipelines where the top-to-bottom order tells a story (e.g. lead → applied → interviewed → hired).
- Comparisons where you want the same category to stay in the same vertical position across columns.
- Stable layouts across data updates, so nodes don't jump position when values change.
When order is omitted, ApexSankey falls back to its automatic crossing-minimization layout.
Keeping order stable across updates
Because the automatic layout can reposition nodes when values change, supplying order is the reliable way to keep a fixed arrangement across re-renders. Recompute or reuse the same order array whenever you call render() with new data:
const order = [
[['LinkedIn', 'Indeed', 'Referral']],
[['Applied']],
[['Responded'], ['No Response']],
[['Interviewed'], ['Rejected']],
[['Accepted']],
]
function draw(nodes, edges) {
sankey.render({ nodes, edges, options: { order } })
}
React example
import { ApexSankey } from 'react-apexsankey'
const data = {
nodes: [
{ id: 'a', title: 'A' },
{ id: 'b', title: 'B' },
{ id: 'c', title: 'C' },
{ id: 'd', title: 'D' },
],
edges: [
{ source: 'a', target: 'c', value: 20, type: 'flow' },
{ source: 'b', target: 'c', value: 15, type: 'flow' },
{ source: 'c', target: 'd', value: 35, type: 'flow' },
],
options: {
order: [
[['a', 'b']],
[['c']],
[['d']],
],
},
}
export default function OrderedSankey() {
return <ApexSankey data={data} options={{ nodeWidth: 20 }} />
}
Note: in the data object, options holds the layout order; visual options like nodeWidth go in the component's options prop (or the constructor options in vanilla JS).