Shadcn Line Chart Generator

Plot trends over time with a shadcn/ui line chart: one line per series, optional smoothing and dots, and automatic date formatting on the axis.

CSV, TSV from Excel/Sheets, a Markdown table, or JSON.

CSV
Style
Tooltip
Code
+57%Growth
Users7.5K
Sessions21.3K
Image
chart.tsx
"use client"

import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"
import {
  type ChartConfig,
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
} from "@/components/ui/chart"

const data = [
  { Week: "Week 1", Users: 1200, Sessions: 3400 },
  { Week: "Week 2", Users: 1450, Sessions: 4100 },
  { Week: "Week 3", Users: 1380, Sessions: 3900 },
  { Week: "Week 4", Users: 1620, Sessions: 4700 },
  { Week: "Week 5", Users: 1890, Sessions: 5200 },
]

const chartConfig = {
  Users: { label: "Users", color: "var(--chart-1)" },
  Sessions: { label: "Sessions", color: "var(--chart-2)" },
} satisfies ChartConfig

/** Tooltip for multi-series charts: the row total plus each series' share. */
function ChartBreakdownTooltip({
  active,
  payload,
  label,
  labelFormatter,
  config,
}: {
  active?: boolean
  payload?: ReadonlyArray<{ dataKey?: unknown; value?: unknown }>
  label?: string | number
  labelFormatter?: (label: unknown) => string
  config: ChartConfig
}) {
  if (!active || !payload?.length) return null

  const entries = payload
    .map((item) => {
      const key = String(item.dataKey)
      const value = Math.abs(Number(item.value))
      return {
        key,
        label: config[key]?.label ?? key,
        color: config[key]?.color ?? "var(--chart-1)",
        value: Number.isFinite(value) ? value : 0,
      }
    })
    .filter((entry) => entry.value > 0)
  if (entries.length === 0) return null

  const total = entries.reduce((sum, entry) => sum + entry.value, 0)
  const stops = entries.map((entry, index) => {
    const before = entries.slice(0, index).reduce((sum, e) => sum + e.value, 0)
    return `${entry.color} ${(before / total) * 100}% ${((before + entry.value) / total) * 100}%`
  })

  return (
    <div className="min-w-52 rounded-xl border border-border bg-card p-3 text-xs shadow-lg">
      <div className="mb-2 flex items-center justify-between gap-3">
        <span className="font-medium text-foreground">
          {label !== undefined && labelFormatter ? labelFormatter(label) : label}
        </span>
        <span className="font-mono font-semibold text-foreground">
          {new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 }).format(total)}
        </span>
      </div>
      <div className="flex items-center gap-3">
        <div
          className="relative size-14 shrink-0 rounded-full"
          style={{ background: `conic-gradient(${stops.join(", ")})` }}
        >
          <div className="absolute inset-1.5 rounded-full bg-card" />
        </div>
        <div className="flex flex-1 flex-col gap-1">
          {entries.map((entry) => (
            <div key={entry.key} className="flex items-center justify-between gap-3">
              <span className="flex items-center gap-1.5 text-muted-foreground">
                <span className="size-1.5 shrink-0 rounded-full" style={{ backgroundColor: entry.color }} />
                <span className="truncate">{entry.label}</span>
              </span>
              <span className="shrink-0 font-medium text-foreground">
                {Math.round((entry.value / total) * 100)}%
              </span>
            </div>
          ))}
        </div>
      </div>
    </div>
  )
}

export function Chart() {
  return (
    <ChartContainer config={chartConfig} className="aspect-auto h-[350px] w-full">
      <LineChart accessibilityLayer data={data}>
        <CartesianGrid vertical={false} strokeDasharray="3 5" />
        <XAxis dataKey="Week" tickLine={false} axisLine={false} tickMargin={10} />
        <YAxis tickLine={false} axisLine={false} tickMargin={8} width={40} tickFormatter={(value) => new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 }).format(value)} />
        <ChartTooltip content={<ChartBreakdownTooltip config={chartConfig} />} />
        <ChartLegend content={<ChartLegendContent />} itemSorter={null} />
        <Line dataKey="Users" type="linear" stroke="var(--color-Users)" strokeWidth={2.5} dot={{ r: 3, fill: "var(--card)", strokeWidth: 2 }} activeDot={{ r: 5, strokeWidth: 2, stroke: "var(--card)" }} />
        <Line dataKey="Sessions" type="linear" stroke="var(--color-Sessions)" strokeWidth={2.5} dot={{ r: 3, fill: "var(--card)", strokeWidth: 2 }} activeDot={{ r: 5, strokeWidth: 2, stroke: "var(--card)" }} />
      </LineChart>
    </ChartContainer>
  )
}

When to use a line chart

Use a line chart when the trend over an ordered axis (usually time) matters more than individual values.

  • Weekly active users and sessions
  • Response times or error rates over time
  • Comparing a few metrics that share one scale

Data format

  • Column 1 is the x-axis in order: dates, weeks, or any ordered label.
  • Blank cells leave a gap in the line instead of dropping it to zero.
  • Paste CSV, JSON from your API, TSV copied from Excel or Google Sheets, or a Markdown table. The generated component keeps your column names as its data keys.
CSV
Week,Users,Sessions
Week 1,1200,3400
Week 2,1450,4100
Week 3,1380,3900
Week 4,1620,4700
Week 5,1890,5200
Same data as JSON
[
  {"week": "Week 1", "users": 1200, "sessions": 3400},
  {"week": "Week 2", "users": 1450, "sessions": 4100},
  {"week": "Week 3", "users": 1380, "sessions": 3900},
  …
]

Options

Smooth
Monotone curves that never overshoot your data, or straight segments.
Dots
Show or hide a hollow dot at every data point.
Tooltip
Breakdown tooltip for multiple series, or shadcn's default.

How to add it to your project

  1. 1. Add the shadcn/ui chart component (it installs Recharts):
    npx shadcn@latest add chart
  2. 2. Paste your data above, pick the options, and copy the generated chart.tsx.
  3. 3. Save it in your project (e.g. components/line-chart.tsx) and render <Chart />, or <Chart data={rows} /> in Data as prop mode.

Line Chart FAQ