StackedBars

<k.StackedBars> stacks one band per column for each x value. Use it for the parts of a total over time (sales per channel per month), or with percent for their shares. Rates such as a conversion rate can ride on top as lines with lines.

Example

byChannel.sql:

-- Orders per channel and month, and the share paid by card
select '2026-01' as month, 60 as web, 40 as store, 100 as total, 71.5 as card_rate
union all select '2026-02', 72, 38, 110, 74.0
union all select '2026-03', 80, 45, 125, 73.2

In report.tsx:

import byChannel from "./byChannel.sql?raw"

type Row = { month: string; web: number; store: number; total: number; card_rate: number }

// in defineReport({ … })
queries: { byChannel: query<Row>(byChannel) },
blocks: (k) => [
  <k.StackedBars
    key="channels"
    series="byChannel"
    x="month"
    xFormat="month"
    y={{ web: "Web", store: "Store" }}
    total="total"
    lines={{ card_rate: "Paid by card" }}
    title="Orders per channel"
    info={{ what: "Orders per channel, with the share paid by card.", sql: ["byChannel"] }}
  />,
],

Props

Also key, description, span (default 1) and info: see Props every block takes.

NameTypeRequiredDefaultMeaning
seriesquery nameyesThe query the rows come from
xcolumnyesThe column along the x axis
ylist of columns, { column: label }, "*" or a function of the datayes, unless metricThe columns stacked, bottom first
titletextyesThe heading
metricmetric namenoDraws a named metric when y is left out
xFormatmonth, period or weeknoas writtenHow x prints, as on line
percenttrue/falsenofalseThe bands are shares (0–100); the axis ends at 100 %
heightheight classnoh-64The plot's height
darkFirsttrue/falsenofalseReverses the colour order, darkest band first
legendtrue/falsenotruefalse hides the legend
yWidthnumbernoThe y axis' width in pixels
counts{column: countColumn}noOn a chart of shares: the hover prints the count behind each band
tooltip{column: label}, {column: {label, format, decimals}} or a function of the datanothe drawn columnsThe hover's rows, for a stack that folds small values into one band
totalcolumnnoPrinted above each bar: the stack's total
labelstrue or list of columnsnoPrints each band's value inside it, dropped when the band is too short
labelDecimals0, 1 or 2no1Decimals of a percent label
lines{column: label} or a function of the datanoLines over the bars, on a right-hand % axis
lineLabelstrue or list of lines columnsnoPrints each point's value on the lines
linesFormatpercent or numbernopercentThe lines are rates, or plain numbers on a compact axis
linesAxisright or leftnorightleft draws the lines on the bars' own axis, such as a target
yDomain[min, max]nofrom zeroThe bars' axis range; each end a number or "auto"
linesDomain[min, max]nofrom zeroThe lines' axis range, such as [0, 100]
splitcolumnnoSmall multiples: one panel per value, shared scales, one legend
overlays{column: label}noBars laid over each band, a little to the right: a subset of its band
scale"sqrt", "log" or a number in (0, 1]nolinearCompresses the axis, for stages that span orders of magnitude
pickPeriod{from: column, to: column}noMakes the chart the date picker: a click on a bar sets the page's range to that row's two date columns
highlightcolumnnothe rows inside the range, with pickPeriodA yes/no column: those bars in the emphasis colour
segmentParams{column: {param: value}} or a function of the datanoA click on a band sets these URL params; null removes one

A stack with negative values is stacked by sign: positive bands up from zero, negative ones down.

Checks

A series that is not one of the report's queries, or a column it names that the query's rows do not have, fails the typecheck, as does a missing required prop or a value of the wrong type.