Line

Line charts join values in order, to show how one or more series trend, rise and fall over time.

LLMs

Code

Line charts are drawn with TanStack Charts, through the kit's Chart components. They paint the chart with the theme's colors, grid and type, and add three palette props. The chart itself is a TanStack definition, written the way TanStack documents it.

Install

npx antuikit@latest init
npx antuikit@latest add tanstack-chart
The first command installs AntuikitProvider and the theme tokens. The second adds the chart components and TanStack Charts itself.

Your first line chart

Describe the chart with defineChart, outside the component, and pass it to Chart. A line is a lineY mark: x names the position field and y the value field.
import { defineChart, lineY } from "@tanstack/charts"
import { scaleLinear } from "@tanstack/charts/scales/linear"
import { scalePoint } from "@tanstack/charts/scales/point"
import { tooltip } from "@tanstack/charts/tooltip"
import { Chart, chartColors, seriesTooltip } from "@/components/ui/tanstack-chart"
const revenueByMonth = [
{ month: "January", revenue: 34 },
{ month: "February", revenue: 52 },
{ month: "March", revenue: 44 },
{ month: "April", revenue: 28 },
]
const definition = defineChart(
{
marks: [
lineY(revenueByMonth, {
id: "Revenue",
x: "month",
y: "revenue",
stroke: chartColors.series[0],
strokeWidth: 2,
}),
],
scales: {
x: { scale: scalePoint },
y: { scale: scaleLinear, grid: true },
},
},
{ focus: "group-x", tooltip: { use: tooltip, content: seriesTooltip } },
)
export function RevenueChart() {
return (
<Chart
definition={definition}
ariaLabel="Revenue by month, in thousands of dollars"
height={200}
/>
)
}
The chart fills its container's width, so give it a height. ariaLabel is required.

Which component

All three take the same definition and the same palette props.
Chart components

Several series

Put every series in one array and name the series field with z and color. The mark draws one line per series.
const definition = defineChart(
{
marks: [
lineY(visitors, {
x: "month",
y: "visitors",
z: "device",
color: "device",
key: (row) => `${row.month}:${row.device}`,
strokeWidth: 2,
}),
],
scales: { x: { scale: scalePoint }, y: { scale: scaleLinear, grid: true } },
color: { domain: ["Desktop", "Mobile"] },
},
{
focus: "group-x",
tooltip: { use: tooltip, sort: "color-domain", content: seriesTooltip },
},
)
  • Give each point a key that is unique across series, or points in the same month share an identity.
  • color: { domain } fixes which series gets which color, so the colors stay put when a series is missing. sort: "color-domain" lists the tooltip rows in that order.
  • focus: "group-x" focuses a whole month, so the tooltip lists every series at that point.

Curve

Lines join their points with straight segments. For another shape, pass a D3 curve through d3Curve. Add d3-shape to your project to import the curves.
import { d3Curve } from "@tanstack/charts"
import { curveMonotoneX, curveStep } from "d3-shape"
lineY(rows, { x: "month", y: "visitors", curve: d3Curve(curveMonotoneX) })
  • curveMonotoneX smooths the line without passing above the highest point or below the lowest. Prefer it over curveNatural, which can overshoot.
  • curveStep holds each value until the next point, for prices and plans.
  • A curve only changes the path between points. It does not smooth the data: compute a moving average for that.

Missing data

A row whose y is null, missing or not a number breaks the line, and the next valid row starts a new segment in the same series. Return null from an accessor for the points you want to leave out.
lineY(rows, {
x: "Date",
// A null value breaks the line, here for every January to March.
y: (row) => (row.Date.getUTCMonth() < 3 ? null : row.Close),
})
Rows are drawn in the order you pass them. Sort them by x before you build the mark.

Markers

points: true draws a small dot on every point. For larger or custom markers, add a dot mark over the same rows and wrap it in decorative, so the tooltip lists each point once.
import { defineChart, dot, lineY } from "@tanstack/charts"
import { decorative } from "@tanstack/charts/mark/decorative"
marks: [
lineY(subscribers, { x: "month", y: "subscribers", strokeWidth: 2 }),
decorative(
dot(subscribers, {
x: "month",
y: "subscribers",
r: 4,
fill: chartColors.series[0],
}),
),
]

Time scale

For dates, pass Date values and a time scale. A point scale spaces the rows evenly, so a missing week takes no room. A time scale spaces them by elapsed time and picks calendar ticks. Add d3-scale to your project for scaleUtc.
import { scaleUtc } from "d3-scale"
const rows = data.map((row) => ({ ...row, date: new Date(row.date) }))
defineChart(
{
marks: [lineY(rows, { x: "date", y: "close" })],
scales: {
x: { scale: scaleUtc },
y: { scale: scaleLinear, grid: true, axis: { label: "Close (USD)" } },
},
},
{
tooltip: {
use: tooltip,
content: (points) => ({
...seriesTooltip(points),
title: (points[0]?.xValue as Date).toLocaleDateString("en-US"),
}),
},
},
)
seriesTooltip prints the x value as text. Override its title to format a date.

Labels at the end

To name each line where it ends instead of in a legend, pick each series' last row with select and draw it with a text mark. Leave room on the right with margin.
import { defineChart, lineY, select, text } from "@tanstack/charts"
const endpoints = select(rows, {
by: "industry",
value: (row) => row.date.getTime(),
select: "max",
})
defineChart({
marks: [
lineY(rows, { x: "date", y: "unemployed", color: "industry" }),
text(endpoints, {
x: "date",
y: "unemployed",
text: "industry",
color: "industry",
anchor: "start",
dx: 6,
}),
],
margin: { top: 16, right: 112, bottom: 28, left: 48 },
// ...scales
})

Colors

The chart takes the theme's chart colors without any setup. Change the palette on the chart itself, or paint one mark with fill and chartColors. The Color guideline covers which palette fits which data.
<Chart definition={definition} ariaLabel="..." palette="multi" />
// One series in a fixed color.
lineY(revenueByMonth, {
x: "month",
y: "revenue",
stroke: chartColors.series[0],
})
Palette props
Taken by Chart, RendererChart and CanvasChart. Rows marked antuikit in the Version column are added by the kit.

Animation

Use RendererChart with TanStack's motion() renderer to animate marks in and between data updates. It skips the animation when the reader has asked for reduced motion.
import { motion } from "@tanstack/charts/motion"
import { RendererChart } from "@/components/ui/tanstack-chart"
const renderer = motion({ initial: "always" })
<RendererChart definition={definition} renderer={renderer} ariaLabel="..." />

API

The options a line chart uses most. TanStack Charts' documentation has the full reference.
lineY