TanStack
Mark Reference

Rules, Links, Arrows, Vectors, and Ticks

These marks cover reference lines, independent segments, directed relationships, fixed-pixel vectors, and compact glyphs. They compose with any other mark and use the chart's shared positional and color scales.

ts
import {
  arrow,
  link,
  ruleX,
  ruleY,
  tickX,
  tickY,
  vector,
} from '@tanstack/charts'

ruleX and ruleY

ruleX draws a vertical rule through the complete inner chart height. ruleY draws a horizontal rule through the complete inner chart width.

ts
ruleX(events, { x: 'date', stroke: '#dc2626' })
ruleY([0], { strokeOpacity: 0.7, strokeDasharray: '4 2' })
ts
function ruleX<TDatum>(
  source: Iterable<TDatum>,
  options?: RuleXOptions<TDatum>,
): ChartMark<never, InferredX, never>

function ruleY<TDatum>(
  source: Iterable<TDatum>,
  options?: RuleYOptions<TDatum>,
): ChartMark<never, never, InferredY>

Options are orientation-specific:

OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
xChannel<TDatum, ChartValue?>Datum itself when it is a chart valueruleX position
yChannel<TDatum, ChartValue?>Datum itself when it is a chart valueruleY position
strokestringTheme foregroundConstant stroke
strokeOpacitynumber0.5Stroke opacity
strokeWidthnumberSVG defaultStroke width
strokeDasharraystringNoneSVG dash array

Rules emit no interaction points and therefore do not participate in native focus or tooltips. Their datum type is intentionally absent from the chart's interaction union.

link draws one independent segment per row. It is appropriate for networks, slopegraphs, error intervals, and annotations. Use lineY when consecutive rows form one path.

ts
link(edges, {
  x1: 'sourceX',
  y1: 'sourceY',
  x2: 'targetX',
  y2: 'targetY',
  z: 'kind',
  key: 'id',
})
ts
function link<TDatum>(
  source: Iterable<TDatum>,
  options: LinkOptions<TDatum>,
): ChartMark<TDatum, InferredEndpointX, InferredEndpointY>
OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
x1, y1required channelsFirst endpoint
x2, y2required channelsSecond endpoint
zChannel<TDatum, ChartKey?>No groupInteraction group and default stroke color
keyChannel<TDatum, ChartKey>Unique id, then indexStable identity
strokeVisualChannel<TDatum, string>Resolved z colorSegment stroke
strokeOpacitynumberSVG defaultStroke opacity
strokeWidthnumber1.5Stroke width
strokeDasharraystringNoneSVG dash array
curveChartCurveStraight ruleOptional path generator

With no curve, the scene contains a rule. With a curve, it contains a two-point polyline with the generated path. The interaction coordinate is the pixel midpoint; semantic xValue and yValue are the second endpoint.

The optional d3Curve bridge and granular algorithm boundary are documented in Line and area and Scales and D3.

arrow

arrow draws one straight directed segment with a fixed-pixel head:

ts
arrow(edges, {
  x1: 'sourceX',
  y1: 'sourceY',
  x2: 'targetX',
  y2: 'targetY',
  headLength: 10,
  headAngle: 28,
})
ts
function arrow<TDatum>(
  source: Iterable<TDatum>,
  options: ArrowOptions<TDatum>,
): ChartMark<TDatum, InferredEndpointX, InferredEndpointY>
OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
x1, y1required channelsTail endpoint
x2, y2required channelsHead endpoint
zChannel<TDatum, ChartKey?>No groupInteraction group and default stroke
keyChannel<TDatum, ChartKey>Unique id, then indexStable identity
strokeVisualChannel<TDatum, string>Resolved z colorArrow stroke
strokeOpacitynumberSVG defaultStroke opacity
strokeWidthnumber1.5Stroke width
headLengthnumber8Head length in pixels, clamped to at least zero
headAnglenumber30Half-angle in degrees

The arrowhead stays the same pixel size as scales and container dimensions change. The interaction coordinate and semantic x/y values are the head endpoint.

vector

vector places a fixed-pixel directed vector at a scaled anchor:

ts
vector(wind, {
  x: 'longitude',
  y: 'latitude',
  length: 'speed',
  rotate: 'bearing',
  anchor: 'middle',
  z: 'region',
})
ts
function vector<TDatum>(
  source: Iterable<TDatum>,
  options: VectorOptions<TDatum>,
): ChartMark<TDatum, InferredX, InferredY>
OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
x, yrequired channelsScaled anchor
lengthnumber | Channel<TDatum, number?>12Vector length in pixels
rotatenumber | Channel<TDatum, number?>0Clockwise degrees; zero points up
anchor'start' | 'middle' | 'end''middle'Which vector position stays at x/y
zChannel<TDatum, ChartKey?>No groupInteraction group and default stroke
keyChannel<TDatum, ChartKey>Unique id, then indexStable identity
strokeVisualChannel<TDatum, string>Resolved z colorStroke
strokeOpacitynumberSVG defaultStroke opacity
strokeWidthnumber1.5Stroke width
headLengthnumber5Head length in pixels, clamped to at least zero
headAnglenumber30Head half-angle in degrees

Length and rotation must be finite. Negative length reverses the body direction while preserving the rotation convention. The interaction point remains the scaled x/y anchor for every anchor mode.

tickX and tickY

Ticks draw a short rule centered at a scaled point:

  • tickX draws a vertical rule, so its length spans the y direction.
  • tickY draws a horizontal rule, so its length spans the x direction.
ts
tickX(rows, { x: 'category', y: 'value', z: 'series' })
tickY(rows, { x: 'value', y: 'category', length: 16 })
ts
function tickX<TDatum>(
  source: Iterable<TDatum>,
  options: TickXOptions<TDatum>,
): ChartMark<TDatum, InferredX, InferredY>

function tickY<TDatum>(
  source: Iterable<TDatum>,
  options: TickYOptions<TDatum>,
): ChartMark<TDatum, InferredX, InferredY>

Both share:

OptionTypeDefaultMeaning
idstringLayer-derivedStable mark ID
x, yrequired channelsTick center
zChannel<TDatum, ChartKey?>No groupInteraction group and default stroke
keyChannel<TDatum, ChartKey>Unique id, then indexStable identity
strokeVisualChannel<TDatum, string>Resolved z colorTick stroke
strokeOpacitynumberSVG defaultStroke opacity
strokeWidthnumber1.5Stroke width
lengthnumberPerpendicular scale bandwidth, otherwise 6Total length before inset
insetnumber0Pixels removed from both ends

Available length is clamped to at least zero after subtracting twice the inset. Each valid row emits one interaction point at the tick center.

Invalid rows and identity

Links, arrows, vectors, and ticks skip rows with any invalid required positional value. Links and arrows require all four endpoints. Stable key channels are especially important for independent segments because keyed reconciliation otherwise falls back to row index.