import { StackedBarChart } from "semiotic"
StackedBarChart visualizes part-to-whole relationships by stacking subcategories within each category bar. Pass your data, specify astackBy field, and get a publication-ready stacked bar chart with color-coded segments, legends, and hover interactions out of the box.
Quick Start
A stacked bar chart requires data andstackBy — the field that defines how bars are subdivided.
import { StackedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: [ { category: "Q1", product: "Widgets", value: 12000 }, { category: "Q1", product: "Gadgets", value: 8000 }, { category: "Q1", product: "Gizmos", value: 5000 }, // ...more data points ], /* --- Layout --- */ stackBy: "product", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ categoryLabel: "Quarter", valueLabel: "Revenue ($)" } export default () => { return <StackedBarChart {...frameProps} /> }
Examples
Horizontal Stacked
Set orientation to "horizontal" for horizontal stacked bars.
import { StackedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: quarterlyData, /* --- Layout --- */ stackBy: "product", orientation: "horizontal", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ categoryLabel: "Quarter", valueLabel: "Revenue ($)" } export default () => { return <StackedBarChart {...frameProps} /> }
Normalized (100%) Stacked
Set normalize to true for a percentage-based stacked chart where each bar sums to 100%.
import { StackedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: [ { category: "2022", region: "North America", value: 340 }, { category: "2022", region: "Europe", value: 280 }, { category: "2022", region: "Asia", value: 190 }, // ...more data points ], /* --- Layout --- */ stackBy: "region", normalize: true, /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ categoryLabel: "Year", valueLabel: "Market Share" } export default () => { return <StackedBarChart {...frameProps} /> }
Custom Color Scheme
Provide a colorScheme array to use your own palette.
import { StackedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: quarterlyData, /* --- Layout --- */ stackBy: "product", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ colorScheme: ["#6366f1", "#f59e0b", "#10b981"], categoryLabel: "Quarter", valueLabel: "Revenue ($)" } export default () => { return <StackedBarChart {...frameProps} /> }
Segment Stroke
Use frameProps.pieceStyle with a CSS custom property to add a dark/light-mode-aware stroke between segments. The canvas renderer resolvesvar(--semiotic-bg) at render time.
import { StackedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: quarterlyData, /* --- Layout --- */ stackBy: "product", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ colorScheme: ["#6366f1", "#f59e0b", "#10b981"], categoryLabel: "Quarter", valueLabel: "Revenue ($)", /* --- Annotate --- */ frameProps: { pieceStyle: () => ({ stroke: "var(--semiotic-bg, #fff)", // adapts to dark/light mode strokeWidth: 1, }), } } export default () => { return <StackedBarChart {...frameProps} /> }
Sorted Stacked Bars
Use sort to order categories by their total value. Accepts "asc", "desc", or a custom comparator. Default is false (preserves insertion order).
import { StackedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: quarterlyData, /* --- Layout --- */ stackBy: "product", sort: "desc", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ categoryLabel: "Quarter", valueLabel: "Revenue ($)" } export default () => { return <StackedBarChart {...frameProps} /> }
Rounded Top (Topmost Segment)
Use roundedTop to round the top corners of bars. For stacked bars, only the topmost segment gets rounded corners — interior segments stay rectangular so they stack cleanly.
import { StackedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: sampleData, /* --- Layout --- */ stackBy: "product", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ colorBy: "product", /* --- Other --- */ roundedTop: 6 } export default () => { return <StackedBarChart {...frameProps} /> }
JSX
<StackedBarChart data={sampleData} categoryAccessor="category" valueAccessor="value" stackBy="product" colorBy="product" roundedTop={6} />
Props
| Prop | Type | Required | Default | Description |
|---|
data | array | Yes | — | Array of data points with category, subcategory, and value fields. |
categoryAccessor | string | function | — | "category" | Field name or function to access category values. |
stackBy | string | function | Yes | — | Field name or function to access subcategory values used for stacking. |
valueAccessor | string | function | — | "value" | Field name or function to access numeric values. |
orientation | "vertical" | "horizontal" | — | "vertical" | Chart orientation. Vertical bars grow upward; horizontal bars grow rightward. |
categoryLabel | string | — | — | Label for the category axis. |
valueLabel | string | — | — | Label for the value axis. |
valueFormat | function | — | — | Format function for value axis tick labels. |
colorBy | string | function | — | stackBy value | Field name or function to determine bar segment color. Defaults to stackBy. |
colorScheme | string | array | — | "category10" | Color scheme name or custom colors array. |
normalize | boolean | — | false | Normalize to 100% (percentage stacked chart). |
barPadding | number | — | 5 | Padding between bar groups in pixels. |
sort | boolean | "asc" | "desc" | function | — | false | Sort categories by total value. Accepts true, "asc", "desc", or a custom comparator. Default false preserves insertion order. |
roundedTop | number | — | — | Rounded corner radius on topmost stack segment. |
animate | boolean | object | — | false | Enable animated intro and smooth data-change transitions. `true` for defaults (300ms ease-out, intro enabled), or `{ duration, easing, intro }`. Set `{ intro: false }` to disable intro. |
enableHover | boolean | — | true | Enable hover annotations on bar segments. |
showGrid | boolean | — | false | Show background grid lines. |
showLegend | boolean | — | true | Show a legend for stacked categories. |
tooltip | object | function | — | — | Tooltip configuration or render function. |
width | number | — | 600 | Chart width in pixels. |
height | number | — | 400 | Chart height in pixels. |
margin | object | — | { top: 50, bottom: 60, left: 70, right: 120 } | Margin around the chart area. |
title | string | — | — | Chart title displayed at the top. |
frameProps | object | — | — | Additional StreamOrdinalFrame props for advanced customization. Escape hatch to the full Frame API. |
Graduating to the Frame
When you need more control — custom marks, mixed piece types, annotations — graduate toStreamOrdinalFrame directly. EveryStackedBarChart is just a configuredStreamOrdinalFrame under the hood.
Chart (simple)
JSX
import { StackedBarChart } from "semiotic" <StackedBarChart data={quarterlyData} categoryAccessor="category" stackBy="product" valueAccessor="value" categoryLabel="Quarter" valueLabel="Revenue" />
Frame (full control)
JSX
import { StreamOrdinalFrame } from "semiotic" <StreamOrdinalFrame data={quarterlyData} oAccessor="category" rAccessor="value" type="bar" pieceIDAccessor="product" style={d => ({ fill: colorScale(d.product) })} oPadding={5} axes={[ { orient: "left", label: "Revenue" }, { orient: "bottom", label: "Quarter" } ]} hoverAnnotation={true} legend={{ legendGroups: [{ styleFn: d => ({ fill: d.color }), items: products.map(p => ({ label: p, color: colorScale(p) })) }] }} size={[600, 400]} margin={{ top: 50, bottom: 60, left: 70, right: 120 }} />
The frameProps prop on StackedBarChart lets you pass any StreamOrdinalFrame prop without fully graduating:
JSX
// Use frameProps as an escape hatch <StackedBarChart data={quarterlyData} stackBy="product" frameProps={{ annotations: [ { type: "or", category: "Q4", label: "Record quarter" } ], connectorStyle: { stroke: "#999" } }} />
- BarChart — simple bar chart without stacking
- DotPlot — a minimal alternative for comparing values across categories
- StreamOrdinalFrame — the underlying Frame with full control over every rendering detail
- Annotations — adding callouts, highlights, and notes to any visualization
- Tooltips — custom tooltip content and positioning