TanStack transforms are eager, deterministic data utilities. Their results can feed a chart, table, export, test, or another transform.
source rows → data transforms → mark channels → mark layoutUse a channel accessor for a one-row calculation, a data transform for reusable cross-row work, and layout: stack() or layout: group() when geometry belongs only to one mark.
const daily = groupBy(orders, {
by: {
region: 'region',
day: ({ datum }) => utcDay.floor(datum.createdAt),
},
outputs: {
revenue: { value: 'amount', reduce: 'sum' },
orders: { reduce: 'count' },
averageOrder: { value: 'amount', reduce: 'mean' },
},
})
const trends = window(daily, {
by: 'region',
orderBy: 'day',
size: 28,
partial: false,
outputs: {
revenue28d: { value: 'revenue', reduce: 'sum' },
averageOrder28d: { value: 'averageOrder', reduce: 'mean' },
},
})
lineY(trends, { x: 'day', y: 'revenue28d', color: 'region' })Unlike a mark-options transform, both intermediate datasets are normal typed rows. Group fields are named and row transforms remain flat.
Field names and object-bag callbacks are interchangeable:
const summaries = groupBy(rows, {
by: { region: 'region', profitable: ({ datum }) => datum.margin > 0 },
outputs: {
p90: { value: 'latency', reduce: quantile(0.9) },
custom: {
reduce: ({ data, group }) => domainCalculation(data, group),
},
},
})For transforms outside the built-ins, use an ordinary function:
const active = rows.filter((row) => row.active)
const enriched = active.map(enrichRow)
const summaries = groupBy(enriched, options)This is the escape hatch and the composition model. There is no pipeline protocol to learn.
const histogram = useMemo(
() => binX(observations, { value: 'latency', thresholds: 24 }),
[observations],
)Use computed, createMemo, $derived, or the equivalent application primitive. TanStack Charts does not add a cache or reactive graph.
Color can infer stack series for stack-capable marks. Grouping remains an explicit geometric choice:
barY(rows, { x: 'quarter', y: 'revenue', color: 'product' })
barY(rows, {
x: 'quarter',
y: 'revenue',
color: 'product',
layout: group(),
})Use stackRowsX or stackRowsY when stack endpoints must be reused outside that mark.
Granular imports such as @tanstack/charts/transform/group and @tanstack/charts/transform/window keep unrelated transform families out of bundle-sensitive code.