Color is a channel. The chart's color configuration defines its semantic mapping, while most marks emit categorical values through z. fill and stroke are literal or data-driven paint overrides; they are not field-name lookups. Bars also expose a separate color channel when subgroup geometry and paint need different fields.
When marks emit group values and no color scale is supplied, TanStack Charts uses the chart theme palette. This is the convenient default for a small, stable set of categories.
For persistent product semantics, supply an explicit configured D3 ordinal scale:
import { scaleOrdinal } from 'd3-scale'
import { colorLegend, defineChart, lineY } from '@tanstack/charts'
const series = ['core', 'react', 'octane'] as const
const color = scaleOrdinal<string, string>()
.domain(series)
.range(['#2563eb', '#f97316', '#10b981'])
const definition = defineChart({
marks: [
lineY(rows, {
x: 'date',
y: 'value',
z: 'series',
key: 'id',
}),
],
x,
y,
color: {
scale: color,
legend: colorLegend({ label: 'Package' }),
},
})The application owns the domain order and paint assignment. This prevents a category from changing color when data is filtered or reordered.
Supply a continuous D3 color scale for numeric values and use colorGradientLegend:
import { scaleSequential } from 'd3-scale'
import { interpolateBlues } from 'd3-scale-chromatic'
import { colorGradientLegend } from '@tanstack/charts'
const color = {
scale: () => scaleSequential(interpolateBlues),
legend: colorGradientLegend({
label: 'Requests per minute',
format: (value) => value.toLocaleString(),
}),
}The factory keeps the interpolator and lets the chart infer the numeric domain from color-channel values. Pass a configured scale instance when the color domain is a product threshold or must remain stable across filtered data.
d3-scale-chromatic and its matching type package are optional direct application dependencies. They are never pulled into charts that do not import them. The D3 integration page owns the install and API-reference links.
colorLegend renders responsive swatches and labels. Options:
The legend reserves its own layout height. It is visual guidance and is hidden from the SVG accessibility tree; essential category meaning should also be available through direct labels, surrounding HTML, or a table.
colorGradientLegend requires a numeric color-scale domain. Options:
The legend communicates the supplied scale. It does not infer thresholds, units, or a meaningful domain from data.
Prefer direct labels when:
Prefer a legend when:
It is valid to use both when the legend establishes the complete domain and direct labels help with the primary comparison.
See Themes and Styling and Accessibility for the surrounding policies.