# Line Chart

Lines through points, for trends and rates over time.

Source: [line-chart.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/line-chart.tsx)

```tsx
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
  ChartGrid,
  ChartLegend,
  ChartTooltip,
  ChartXAxis,
  ChartYAxis,
  type ChartConfig,
} from "@/components/ui/chart";
import { LineChart, LineChartSeries } from "@/components/ui/line-chart";

const data = [
  { time: "00:00", p50: 82, p95: 210 },
  { time: "02:00", p50: 78, p95: 196 },
  { time: "04:00", p50: 75, p95: 188 },
  { time: "06:00", p50: 88, p95: 232 },
  { time: "08:00", p50: 104, p95: 286 },
  { time: "10:00", p50: 118, p95: 342 },
  { time: "12:00", p50: 126, p95: 368 },
  { time: "14:00", p50: 121, p95: 351 },
  { time: "16:00", p50: 112, p95: 318 },
  { time: "18:00", p50: 99, p95: 274 },
  { time: "20:00", p50: 92, p95: 248 },
  { time: "22:00", p50: 86, p95: 224 },
];

const config = {
  p50: { label: "p50" },
  p95: { label: "p95" },
} satisfies ChartConfig;

export default function LineChartLatency() {
  return (
    <Card className="w-full">
      <CardHeader>
        <CardTitle>Response time</CardTitle>
        <CardDescription>Last 24 hours</CardDescription>
      </CardHeader>
      <CardContent>
        <LineChart data={data} config={config} className="aspect-[4/3] sm:aspect-[2/1]">
          <ChartGrid />
          <ChartXAxis dataKey="time" />
          <ChartYAxis tickFormatter={(ms: number) => `${ms} ms`} />
          <ChartTooltip valueFormatter={(ms) => `${ms} ms`} />
          <ChartLegend />
          <LineChartSeries dataKey="p50" />
          <LineChartSeries dataKey="p95" />
        </LineChart>
      </CardContent>
    </Card>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

```bash
npx shadcn@latest add @jarvis/line-chart
```

## Usage

```tsx
import { ChartTooltip, ChartXAxis, type ChartConfig } from "@/components/ui/chart";
import { LineChart, LineChartSeries } from "@/components/ui/line-chart";

const data = [
  { month: "January", visitors: 186 },
  { month: "February", visitors: 305 },
  { month: "March", visitors: 237 },
];

const config = {
  visitors: { label: "Visitors" },
} satisfies ChartConfig;

export function VisitorsChart() {
  return (
    <LineChart data={data} config={config}>
      <ChartXAxis dataKey="month" />
      <ChartTooltip />
      <LineChartSeries dataKey="visitors" />
    </LineChart>
  );
}
```

`LineChartSeries` draws one series. The axes, tooltip, legend and config come from
[Chart](https://ui.jarv.is/components/chart.md).

## Composition

- `LineChart`
  - [`ChartGrid`](https://ui.jarv.is/components/chart.md)
  - [`ChartXAxis`](https://ui.jarv.is/components/chart.md)
  - [`ChartYAxis`](https://ui.jarv.is/components/chart.md)
  - [`ChartTooltip`](https://ui.jarv.is/components/chart.md)
  - [`ChartLegend`](https://ui.jarv.is/components/chart.md)
  - `LineChartSeries`

## Examples

### Dots

`dots` marks every point. This one also uses `curve="linear"`.

```tsx
import { ChartGrid, ChartTooltip, ChartXAxis, type ChartConfig } from "@/components/ui/chart";
import { LineChart, LineChartSeries } from "@/components/ui/line-chart";

const data = [
  { month: "January", signups: 186 },
  { month: "February", signups: 305 },
  { month: "March", signups: 237 },
  { month: "April", signups: 273 },
  { month: "May", signups: 209 },
  { month: "June", signups: 314 },
];

const config = {
  signups: { label: "Signups" },
} satisfies ChartConfig;

export default function LineChartDots() {
  return (
    <LineChart data={data} config={config} curve="linear" className="max-w-lg">
      <ChartGrid />
      <ChartXAxis dataKey="month" tickFormatter={(month: string) => month.slice(0, 3)} />
      <ChartTooltip />
      <LineChartSeries dataKey="signups" dots />
    </LineChart>
  );
}
```

### Target

A dashed series works for a target, and `curve="stepAfter"` holds it level until it changes. The
y-axis starts at zero; `domain={["auto", "auto"]}` fits it to the data instead.

```tsx
import {
  ChartGrid,
  ChartLegend,
  ChartTooltip,
  ChartXAxis,
  ChartYAxis,
  type ChartConfig,
} from "@/components/ui/chart";
import { LineChart, LineChartSeries } from "@/components/ui/line-chart";

const data = [
  { week: "Week 1", orders: 412, target: 450 },
  { week: "Week 2", orders: 468, target: 450 },
  { week: "Week 3", orders: 431, target: 500 },
  { week: "Week 4", orders: 527, target: 500 },
  { week: "Week 5", orders: 489, target: 550 },
  { week: "Week 6", orders: 583, target: 550 },
];

const config = {
  orders: { label: "Orders" },
  target: { label: "Target", color: "var(--chart-5)" },
} satisfies ChartConfig;

export default function LineChartTarget() {
  return (
    <LineChart data={data} config={config} className="max-w-lg">
      <ChartGrid />
      <ChartXAxis dataKey="week" />
      <ChartYAxis domain={["auto", "auto"]} />
      <ChartTooltip indicator="line" />
      <ChartLegend />
      <LineChartSeries dataKey="orders" />
      <LineChartSeries dataKey="target" curve="stepAfter" dashed />
    </LineChart>
  );
}
```

### Steps

`curve="step"` suits counts that jump between values.

```tsx
import { ChartGrid, ChartTooltip, ChartXAxis, type ChartConfig } from "@/components/ui/chart";
import { LineChart, LineChartSeries } from "@/components/ui/line-chart";

const data = [
  { time: "09:00", servers: 4 },
  { time: "10:00", servers: 6 },
  { time: "11:00", servers: 6 },
  { time: "12:00", servers: 9 },
  { time: "13:00", servers: 8 },
  { time: "14:00", servers: 11 },
  { time: "15:00", servers: 7 },
  { time: "16:00", servers: 5 },
];

const config = {
  servers: { label: "Servers" },
} satisfies ChartConfig;

export default function LineChartStep() {
  return (
    <LineChart data={data} config={config} curve="step" className="max-w-lg">
      <ChartGrid />
      <ChartXAxis dataKey="time" />
      <ChartTooltip />
      <LineChartSeries dataKey="servers" />
    </LineChart>
  );
}
```

## Props

| Part | Extends |
| --- | --- |
| `LineChart` | [`Chart`](https://ui.jarv.is/components/chart.md) |
| `LineChartSeries` | `Line` |

### LineChart

| Prop        | Type                        | Description                                                                         |
| ----------- | --------------------------- | ----------------------------------------------------------------------------------- |
| `config`    | `ChartConfig`               | Each series' label, icon and color, keyed by its data key.                          |
| `data`      | `Record<string, unknown>[]` | The rows to plot, one object per point along the x-axis.                            |
| `curve?`    | `CurveType`                 | How lines between points are drawn. A series can set its own. Default: `"monotone"` |
| `children?` | `React.ReactNode`           |                                                                                     |

### LineChartSeries

| Prop      | Type        | Description                                                                   |
| --------- | ----------- | ----------------------------------------------------------------------------- |
| `dataKey` | `string`    | The key of the series' values in each row, which also names it in the config. |
| `curve?`  | `CurveType` | How lines between points are drawn. Defaults to the chart's `curve`.          |
| `dashed?` | `boolean`   | Draws the line dashed, as for a forecast or a target. Default: `false`        |
| `dots?`   | `boolean`   | Marks every point, not just the hovered one. Default: `false`                 |

`LineChartSeries` takes the props of Recharts'
[`Line`](https://recharts.github.io/en-US/api/Line/) too, such as `connectNulls`.
