TanStack
Mark Reference

Line and Area Marks

Line and area marks consume an iterable directly. Channels may be compatible field names or accessors. Rows whose required positional value is null, undefined, invalid, or nonfinite create gaps instead of connecting across missing data.

ts
import {
  areaX,
  areaY,
  defineChart,
  lineX,
  lineY,
  stack,
} from '@tanstack/charts'

lineY

lineY connects consecutive valid rows within each path group. An explicit z defines the groups. When z is omitted and color is present, color defines them.

ts
const mark = lineY(rows, {
  x: 'date',
  y: 'value',
  z: 'series',
  points: true,
})
ts
function lineY<TDatum>(
  source: Iterable<TDatum>,
  options?: LineYOptions<TDatum>,
): ChartMark<TDatum, InferredX, number>

Options

OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
xChannel<TDatum, ChartValue?>Row indexHorizontal value
yChannel<TDatum, number?>Numeric datumVertical value
zChannel<TDatum, ChartKey?>No explicit groupPath grouping; overrides color grouping
colorChannel<TDatum, ChartKey?>zColor-scale value; groups when z is absent
keyChannel<TDatum, ChartKey>Top/nested id, x, then indexStable interaction and scene identity
strokeVisualChannel<TDatum, string>Resolved colorFinal path paint; evaluated from the first row
strokeOpacitynumberSVG defaultStroke opacity
strokeWidthnumber2.25Stroke width
strokeDasharraystringNoneSVG dash array
pointsbooleanfalseDraws a radius-2.5 dot at each valid point
curveChartCurveStraight segmentsOptional path generator
statesreadonly ChartMarkState[]NoneFocus-driven presentation overrides

Input order is path order. Sort rows before creating the mark when semantic x order differs from input order. A null row flushes the current segment; later valid rows begin a new segment in the same group.

Each valid row emits one interaction point at its scaled x/y coordinate. groupLabel is the string form of the effective path group, or the mark ID without a group.

lineX

lineX is the transposed line mark. It connects numeric x values along a numeric, categorical, or temporal y channel:

ts
const mark = lineX(rows, {
  x: 'value',
  y: 'category',
  z: 'series',
  points: true,
})
ts
function lineX<TDatum>(
  source: Iterable<TDatum>,
  options?: LineXOptions<TDatum>,
): ChartMark<TDatum, number, InferredY>

Its options transpose lineY: x is the numeric value channel and defaults to a numeric datum; y is the longitudinal ChartValue channel and defaults to row index. Identity falls back to y, invalid rows create segment gaps, and input order remains path order. Grouping, paint, points, curves, states, and motion use the same contract. Line interaction follows y affinity so keyboard and pointer traversal match the longitudinal axis.

areaY

areaY fills between a numeric upper channel and a numeric lower baseline along x.

ts
const mark = areaY(rows, {
  x: 'date',
  y1: 'low',
  y2: 'high',
  z: 'series',
})
ts
function areaY<TDatum>(
  source: Iterable<TDatum>,
  options?: AreaYOptions<TDatum>,
): ChartMark<TDatum, InferredX, number>

Options

OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
xChannel<TDatum, ChartValue?>Row indexShared horizontal position
yChannel<TDatum, number?>Numeric datumLayer thickness; implicitly stacked at each x
y1number | Channel<TDatum, number?>Implicit stack startExplicit lower boundary
y2number | Channel<TDatum, number?>Implicit stack endExplicit upper boundary; takes precedence over y
zChannel<TDatum, ChartKey?>No explicit groupArea grouping; overrides color grouping
colorChannel<TDatum, ChartKey?>zColor-scale value; groups when z is absent
keyChannel<TDatum, ChartKey>Top/nested id, x, then indexStable interaction identity
fillVisualChannel<TDatum, string>Resolved colorFinal area paint; evaluated from the group's first row
fillOpacitynumber0.2Fill opacity
strokeVisualChannel<TDatum, string>NoneOptional boundary stroke, evaluated from the group's first row
strokeWidthnumberSVG defaultBoundary stroke width
curveChartCurveStraight segmentsOptional path generator
layoutStackLayoutImplicit diverging stackConfigured stack order or offset
statesreadonly ChartMarkState[]NoneFocus-driven presentation overrides

Without explicit endpoints, repeated x positions stack by series. z defines series; a discrete color channel may infer it when z is absent. Use layout: stack(options) for explicit order, reversal, normalization, centering, or wiggle offset. Supplying y1 or y2 opts out and preserves authored interval boundaries.

Use order: 'inside-out' with offset: 'wiggle' for nonnegative streamgraphs. Inside-out order follows series peaks and totals. The completed wiggle stack is translated once so the global minimum start is zero; individual positions are not rebased. Positions and series retain first-seen order, and a missing position/series pair contributes zero to layout without emitting a synthetic point.

Input order and null-gap behavior match the line marks. Each valid row emits one point at the upper y2/y value, not at the lower baseline.

areaX

areaX is the transposed interval area: it fills between left and right numeric x values along y.

ts
const mark = areaX(rows, {
  y: 'category',
  x1: 'minimum',
  x2: 'maximum',
  z: 'series',
})
ts
function areaX<TDatum>(
  source: Iterable<TDatum>,
  options?: AreaXOptions<TDatum>,
): ChartMark<TDatum, number, InferredY>

Options

OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
xChannel<TDatum, number?>Numeric datumLayer thickness; implicitly stacked at each y
x1number | Channel<TDatum, number?>Implicit stack startExplicit left boundary
x2number | Channel<TDatum, number?>Implicit stack endExplicit right boundary; takes precedence over x
yChannel<TDatum, ChartValue?>Row indexShared vertical position
zChannel<TDatum, ChartKey?>No explicit groupArea grouping; overrides color grouping
colorChannel<TDatum, ChartKey?>zColor-scale value; groups when z is absent
keyChannel<TDatum, ChartKey>Top/nested id, y, then indexStable interaction identity
fillVisualChannel<TDatum, string>Resolved colorFinal paint, evaluated from the group's first row
fillOpacitynumber0.2Fill opacity
strokeVisualChannel<TDatum, string>NoneOptional boundary stroke
strokeWidthnumberSVG defaultBoundary stroke width
curveAreaXCurveStraight segmentsOptional transposed path generator
layoutStackLayoutImplicit diverging stackConfigured stack order or offset
statesreadonly ChartMarkState[]NoneFocus-driven presentation overrides

Without explicit endpoints, repeated y positions stack by series. Supplying x1 or x2 opts out and preserves authored interval boundaries. Each valid row emits one point at its right x2/x value.

Line and area paths have one paint value. When both channels are present, z wins for grouping and color may supply a different semantic paint value. Keep color constant within each explicit z group; the first row supplies the path color.

Curves

Line and area marks accept a small path-generation contract rather than bundling interpolation algorithms:

ts
interface ChartCurve {
  line(points: readonly (readonly [number, number])[]): string
  area(
    top: readonly (readonly [number, number])[],
    bottom: readonly (readonly [number, number])[],
  ): string
}

interface AreaXCurve {
  areaX(
    right: readonly (readonly [number, number])[],
    left: readonly (readonly [number, number])[],
  ): string
}

Optional adapters are available:

ts
import { d3AreaXCurve } from '@tanstack/charts/d3/area-x'
import { d3Curve } from '@tanstack/charts/d3/shape'

They accept a supplied curve factory and return the corresponding TanStack contract. Which granular D3 module to install and why these algorithms remain injected is documented once in Scales.

Layering area and line

Area marks do not automatically draw their upper line. Compose the layers:

ts
const definition = defineChart({
  marks: [
    areaY(rows, {
      x: 'date',
      y: 'value',
      z: 'series',
      fillOpacity: 0.16,
    }),
    lineY(rows, {
      x: 'date',
      y: 'value',
      z: 'series',
    }),
  ],
  x: { scale: xScale },
  y: { scale: yScale },
})

Use matching channels and scales when the two layers must align. Identity inference is evaluated independently for every interactive layer; supply a key only where its automatic candidate is not stable.