Line Chart

Draws one line per series across an ordered domain, themed by your design system.

const chartData = /* ... */;

<div className="w-full">
  <LineChart
    data={chartData}
    x="month"
    y={['desktop', 'mobile']}
    curve="monotone"
    labels={{ desktop: 'Desktop', mobile: 'Mobile' }}
    ariaLabel="Desktop and mobile visitors, January through June"
  />
</div>

LineChart answers how a value changes across an ordered domain. Give it rows and the fields to read — it builds the scales, the axes, the legend, the tooltip, and the keyboard navigation for you, all colored from your palette.

Installation

npx shadcn@latest add @dotui/chart-line

It brings the chart core — the host, the palette, and the shared frame — along with it.

Usage

import { LineChart } from '@/ui/chart-line'
const chartData = [
  { month: 'Jan', desktop: 186 },
  { month: 'Feb', desktop: 305 },
  { month: 'Mar', desktop: 237 },
]

export function Example() {
  return (
    <LineChart
      data={chartData}
      x="month"
      y="desktop"
      labels={{ desktop: 'Desktop' }}
      legend={false}
      ariaLabel="Desktop visitors, January through March"
    />
  )
}

x and y name fields on the row; labels gives each series a display name for the legend and the tooltip. data is compared by identity, so define it outside your component — or memoize it — and the chart rebuilds only when the rows actually change.

Wide and long data

Two data shapes, one component. Wide rows carry one field per series:

<LineChart data={rows} x="month" y={['desktop', 'mobile']} />

Long rows repeat the x value and name their series in a field:

<LineChart data={rows} x="month" y="visitors" series="device" />

Either way, series are colored in order from --chart-1 onward. Pass seriesOrder to fix that order yourself instead of taking it from the field order or the row order.

Curve

curve chooses the path between points: natural (the default), monotone, step, or linear.

<LineChart data={rows} x="month" y="desktop" curve="step" />

Interpolation only changes how the line travels between observations — it does not smooth the data or claim anything about the values in between. A null value is a gap, not a zero: the line stops and restarts on the far side.

Annotations

marks paints extra layers over the lines, marksBefore under them. Both take marks straight from @tanstack/charts, so labels, reference rules, and custom dots compose with the same scales:

import { text } from '@tanstack/charts/text'

const labels = text(chartData, {
  x: 'month',
  y: 'desktop',
  text: 'desktop',
  z: () => 'Desktop',
  dy: -12,
})

Give an annotation the same z as the series it belongs to — the series' display name, or its field name when you pass no labels. That keeps it in one focus group with the line, so the tooltip stays a single row instead of growing one per layer. Build marks outside render: like data, they are compared by identity.

Accessibility

ariaLabel is required — a chart is a figure, not decoration. Name what is being compared, and add ariaDescription for context that is not already visible next to the chart.

The chart surface is keyboard-focusable. Focusing it selects the first point; Arrow keys move between points, Home and End jump to the ends, Enter or Space pins the tooltip, and Escape dismisses it. When exact values matter, put a real table or a short summary next to the chart — HTML the reader can select, translate, and print.

Examples

Default

Multiple Series

Linear

Step

Dots

Custom Dots

Dot Colors

Labels

Custom Labels

API Reference

LineChart

Line chart. Give it rows plus the fields to read: one `y` field per series for wide rows, or a single `y` with `series` for long rows. Interaction and animation props are shared by every family — see `ChartBehaviorProps` — and the host props (`height`, `width`, `className`, callbacks) live on `Chart`.

PropType
readonly unknown[]
string
readonly string[] | string
string
string
readonly string[]
Readonly<Record<string, string>>
string
ChartCurve
number
boolean
boolean
boolean
boolean
ChartFormat
ChartFormat
string
readonly ChartMarkLayer[]
readonly ChartMarkLayer[]
ReactNode

Interaction and animation props are shared by every chart family:

Interaction and animation props shared by every chart family component. They are flat scalars on purpose: the chart definition is memoized on a serialized key, and a nested option object would silently go stale.

PropType
ChartFocus
number
ChartTooltipAnchor
boolean
false
ChartAnimate

The host props — height, width, className, and the focus callbacks — are documented on the Chart page.

Last updated on 8/1/2026