import { SwimlaneChart } from "semiotic"
SwimlaneChart renders categorical lanes with items stacked sequentially within each lane, colored by subcategory. Unlike a stacked bar chart, the same subcategory can appear multiple times in the same lane — items stack left-to-right (horizontal) or bottom-to-top (vertical) in the order they appear in data. It wrapsStreamOrdinalFrame withchartType="swimlane" and supports both static data and the push API for streaming.
Quick Start
Pass data for static mode, or omit it and useref.current.push() for streaming. Each datum needs a lane (categoryAccessor), a subcategory (subcategoryAccessor), and a size (valueAccessor).
JSX
import { SwimlaneChart } from "semiotic" // Static <SwimlaneChart data={[ { lane: "Backend", task: "Auth", value: 3 }, { lane: "Backend", task: "DB", value: 5 }, { lane: "Backend", task: "Auth", value: 2 }, { lane: "Frontend", task: "UI", value: 6 }, { lane: "Frontend", task: "API", value: 3 }, ]} categoryAccessor="lane" subcategoryAccessor="task" valueAccessor="value" colorBy="task" orientation="horizontal" enableHover showLegend /> // Streaming const ref = useRef() ref.current.push({ lane: "Backend", task: "Auth", value: 2 }) <SwimlaneChart ref={ref} categoryAccessor="lane" subcategoryAccessor="task" valueAccessor="value" colorBy="task" orientation="horizontal" enableHover showLegend />
Brush + Zoom
Use brush to enable value-axis selection on the overview chart, then pass the brushed range as frameProps.rExtent to a detail chart to zoom in.
JSX
const [extent, setExtent] = useState(null) {/* Overview — brushable */} <SwimlaneChart data={tasks} categoryAccessor="lane" subcategoryAccessor="task" valueAccessor="value" brush onBrush={setExtent} height={180} /> {/* Detail — zoomed to brushed region */} <SwimlaneChart data={tasks} categoryAccessor="lane" subcategoryAccessor="task" valueAccessor="value" frameProps={extent ? { rExtent: extent.r } : undefined} height={220} />
Themed Borders
Use frameProps.pieceStyle to add a stroke between swimlane items that adapts to dark and light mode. The CSS custom propertyvar(--semiotic-bg) resolves to the chart background color, so borders always match the surrounding area.
JSX
<SwimlaneChart data={data} categoryAccessor="lane" subcategoryAccessor="task" valueAccessor="value" colorBy="task" orientation="horizontal" frameProps={{ pieceStyle: () => ({ stroke: "var(--semiotic-bg, #fff)", // adapts to dark/light mode strokeWidth: 1, }), }} />
Gradient Fill + Threshold
Pass gradientFill with colorStops to render a multi-stop gradient along each segment’s growth direction (left→right horizontal, bottom→top vertical). The shape matches BarChart andAreaChart. Combine with anx-threshold annotation to drop an unlabeled dashed vertical line at any value — useful for SLO/budget markers.
The same gradient + threshold combo also works in sparklinemode — chrome strips off but the track, gradient, and dashed threshold remain. Useful for inline status indicators in tables and dashboards.
Q3 budget75% of $1.2M
JSX
<SwimlaneChart data={[{ lane: "Budget", phase: "spend", value: 75 }]} categoryAccessor="lane" subcategoryAccessor="phase" valueAccessor="value" orientation="horizontal" frameProps={{ rExtent: [0, 100] }} // Track sized to the lane's bandwidth, full value-axis width. // Semi-transparent grey naturally contrasts in both light and dark mode. trackFill="rgba(127, 127, 127, 0.25)" gradientFill={{ colorStops: [ { offset: 0, color: "#9ca3af" }, // grey from 0%... { offset: 50/75, color: "#9ca3af" }, // ...to 50% (hard transition) { offset: 50/75, color: "#fbbf24" }, // yellow from 50%... { offset: 62.5/75, color: "#f97316" }, // ...through orange... { offset: 1, color: "#dc2626" }, // ...to red at 75% ], }} annotations={[ { type: "x-threshold", value: 50, color: "var(--semiotic-text)" }, ]} />
Rounded Corners
Pass roundedTop (pixels) to round the outermost ends of each lane — left and right in horizontal orientation, top and bottom in vertical. Middle segments of multi-segment lanes stay square so adjacent pieces visually butt against each other. Single-segment lanes round all four corners.
JSX
<SwimlaneChart data={projectTasks} categoryAccessor="team" subcategoryAccessor="task" valueAccessor="value" roundedTop={8} />
Props
| Prop | Type | Required | Default | Description |
|---|
data | array | — | — | Data array. Omit for push API mode. |
categoryAccessor | string | function | — | "category" | Accessor for lane categories (swim lanes). |
subcategoryAccessor | string | function | Yes | — | Accessor for item subcategory (color grouping within lanes). Duplicate subcategories in the same lane stack sequentially. |
valueAccessor | string | function | — | "value" | Accessor for item size/duration along the value axis. |
orientation | "horizontal" | "vertical" | — | "horizontal" | Horizontal renders lanes as rows; vertical as columns. |
colorBy | string | function | — | subcategoryAccessor | Color accessor. Defaults to subcategoryAccessor. |
colorScheme | string | string[] | — | "category10" | Color scheme for subcategories. |
barPadding | number | — | 40 | Padding between lanes in pixels. |
roundedTop | number | — | — | Rounded corner radius (px) applied to the outermost ends of each lane — left+right for horizontal, top+bottom for vertical. Middle segments stay square; single-segment lanes round all four corners. |
enableHover | boolean | — | — | Enable hover annotations on items. |
showGrid | boolean | — | — | Show grid lines. |
showCategoryTicks | boolean | — | — | Show lane labels on the category axis. |
showLegend | boolean | — | — | Show a legend keyed to subcategory colors. |
legendPosition | "right" | "left" | "top" | "bottom" | — | "right" | Legend position. |
tooltip | boolean | function | object | — | — | Tooltip configuration. |
width | number | — | 600 | Chart width. |
height | number | — | 400 | Chart height. |
margin | object | — | — | Chart margins: { top, right, bottom, left }. |
brush | boolean | — | — | Enable value-axis brush selection. |
onBrush | function | — | — | Callback with { r: [min, max] } or null when brush clears. |
linkedBrush | string | object | — | — | LinkedCharts brush integration name. |
gradientFill | boolean | { topOpacity, bottomOpacity } | { colorStops } | — | — | Gradient fill across each segment along its growth direction (left→right horizontal, bottom→top vertical). Same shape as BarChart/AreaChart gradientFill. |
trackFill | string | { color, opacity } | — | — | Lane "track" fill — a rect drawn behind each lane spanning the full value-axis range, sized to the lane's bandwidth. CSS vars supported (e.g. "var(--semiotic-grid)"). |
annotations | array | — | — | Annotation objects. Supports x-threshold for unlabeled dashed vertical reference lines (omit label). |
frameProps | object | — | — | Pass-through props to StreamOrdinalFrame for advanced control. |
Graduating to the Frame
For full control — custom item rendering, mixed chart types, or advanced annotation logic — graduate toStreamOrdinalFrame directly.
Chart (simple)
JSX
import { SwimlaneChart } from "semiotic" <SwimlaneChart data={tasks} categoryAccessor="lane" subcategoryAccessor="task" valueAccessor="value" colorBy="task" orientation="horizontal" enableHover />
Frame (full control)
JSX
import { StreamOrdinalFrame } from "semiotic" <StreamOrdinalFrame chartType="swimlane" data={tasks} oAccessor="lane" rAccessor="value" stackBy="task" projection="horizontal" pieceStyle={(d) => ({ fill: colorMap[d.task] })} enableHover size={[600, 300]} />