Component

LineChart

Multi-series line chart for continuous-y trends over time — season stories, rolling averages, form curves. Built-in linear-regression trendlines, event-annotation guides, and an optional mirrored y-axis. Hero fixture: a synthetic two-series xG / xGA season trend.

Change of ManagerChange of Manager05101520253035Matchweek00.511.522.500.511.522.5
xGA1.80
xG1.40
Stories

Canonical behaviors.

Empty State

No series supplied — the chart stays explicit.

No data
Sparse Series

Minimal valid chart: one series, a handful of points.

11.522.533.54Round11.21.41.61.822.2
Team A2.20
Trendlines

Linear-regression overlay per series. Extends across the full axis range, not just the data x-min/x-max.

05101520253035Matchweek00.511.522.5
xGA1.80
xG1.40
Trendlines Only

`showMarkers={false}` plus trendlines for a noise-free form read.

05101520253035Matchweek00.511.522.5
xGA1.80
xG1.40
Dual Y Axis

Mirrored ticks on the right keep the y-read legible at wider widths.

05101520253035Matchweek00.511.522.500.511.522.5
xGA1.80
xG1.40
Event Annotations

Vertical guides mark managerial changes, season cuts, or other narrative beats.

Change of ManagerChange of Manager05101520253035Matchweek00.511.522.5
xGA1.80
xG1.40
Highlighted Series

Emphasize a subset and let the rest drop into the background.

05101520Round23456789
Series 17.19
Series 43.48
Per-Point Marker Kinds

Set `markerKind` on individual points to switch their default shape. Consumers can still override via the `points.shape` style callback.

1234567Matchweek0.811.21.41.61.8
Form1.30
Dark Theme

ThemeProvider restyles the chart without touching the series shape.

05101520253035Matchweek00.511.522.500.511.522.5
xGA1.80
xG1.40
Static Export Mode

Suppresses hover and HTML label overlay for export / SSR contexts.

05101520253035Matchweek00.511.522.5
Required-rate pace

`series-pair` envelope between actual cumulative points and a 68-pt top-4 pace threshold. Green when the team is ahead of the pace, red when behind. The reference line opts out of markers and uses per-series `strokeDasharray` to read as a threshold, not a trajectory. Synthetic slow-start / late-surge season crosses pace around MW22.

0510152025303540Matchweek01020304050607080Cumulative pts
Team (actual)75.00
Top-4 pace68.00
Aging curve ± σ

`envelopeCenterOffset()` helper builds a ±σ ribbon around the position-group mean. Player trajectory overlaid for contrast.

182022242628303234Age0.10.20.30.40.50.60.7G+A / 90
Position mean (AM)0.26
Player0.18
Rolling form CI

Single-series confidence band via `envelopeCenterOffset()`. Rolling xG/90 with ±σ.

051015202530Match0.60.811.21.41.6xG / 90
Rolling xG/901.38
Elo river with zones

`bands` for title-race, mid-table, and relegation zones; `eventRef()` marks a point-in-time beat (here, a managerial change).

Title raceTitle raceRelegationRelegationNew managerNew manager0510152025303540Matchweek020406080100Elo
Rolling rating48.00
Lorenz curve (single source of truth)

Diagonal reference + `series-to-reference` envelope between the Lorenz curve and the equality diagonal. The reference line's geometry is the single source of truth — no hidden-series duplication. Canonical z-order acceptance test: dashed diagonal above the red fill, Lorenz curve above everything.

Perfect equalityPerfect equality00.20.40.60.81Cumulative club share00.20.40.60.81Cumulative pts share
Cumulative pts share1.00
Usage

Best-practice examples.

Minimal usage

Pass one or more series, each with an array of { x, y } points.

                    import { LineChart } from "@withqwerty/campos-react";

export function SeasonTrend({ xg, xga }) {
  return (
    <LineChart
      series={[
        { id: "xg", label: "xG", points: xg },
        { id: "xga", label: "xGA", points: xga },
      ]}
      xAxisLabel="Matchweek"
    />
  );
}
                  
With trendlines and reference annotations

Linear-regression trendlines per series plus declarative reference lines for narrative events.

                    import { LineChart, eventRef, EVENT_REF_SUBTLE } from "@withqwerty/campos-react";

<LineChart
  series={series}
  trendlines
  dualYAxis
  references={[
    eventRef(12, { label: "Change of Manager" }),
    eventRef(20, EVENT_REF_SUBTLE),
  ]}
  xAxisLabel="Matchweek"
/>
                  
API

Public surface.

Prop Type Default Description
series readonly LineChartSeriesInput[] required Array of { id, label?, color?, points, trendline? } — one entry per line.
xDomain / yDomain readonly [number, number] auto from data Explicit axis range. Omit to let nice-ticks pick round boundaries.
xTicks / yTicks readonly number[] | number auto Explicit tick values or tick count. Number = count, array = positions.
xTickFormat / yTickFormat (value: number) => string locale number Tick formatter — use to render dates, percentages, etc.
xAxisLabel / yAxisLabel string "" Axis caption below / left of the plot area.
trendlines boolean false Draw a linear-regression trendline for every series. Opt out per series via `series[].trendline: false`.
dualYAxis boolean false Mirror y-axis ticks on the right side for wide charts.
references readonly PlotAreaReferenceLine[] [] Declarative horizontal/vertical/diagonal reference lines. Use `eventRef(x, opts?)` for any point-in-time marker (manager change, ownership, injury, external event) — pass `EVENT_REF_SUBTLE` or `EVENT_REF_ACCENT` to restyle. Use `diagonalFromLinear` for regression / equality lines.
bands readonly PlotAreaBand[] [] Axis-aligned shaded rectangles over data space. Handy for zone ribbons (title race, relegation, good/bad bands).
envelopes readonly LineChartEnvelope[] [] Signed-area fills between two bounds. Three kinds: `series-pair`, `center-offset` (CI-around-centre via `envelopeCenterOffset`), `series-to-reference` (Lorenz / regression-band). Each envelope clips to the plot area by default — set `clip: false` when overflow is intentional.
highlightSeries readonly string[] Series ids to emphasize; all others fade to backgroundOpacity.
showMarkers boolean true Show dot markers at each data point.
showGridLines boolean true Show horizontal grid lines at each y-tick.
showEndLabels / endLabelsForAllSeries boolean true / false Anchored labels at the last point of each series. Default: only highlighted series.
lineTooltip { renderContent: (series) => ReactNode } Cursor-following tooltip rendered while hovering along any line. Receives the full series model for derived stats.
tooltipPriority "marker" | "line" | "both" "marker" Resolves overlap between the marker tooltip and the cursor-following lineTooltip. Default: marker wins.
formatAccessibleX (x: number) => string String(x) Formats the x value inside marker aria-labels and the tooltip's x-row. Use when x is an epoch-ms timestamp or other non-human-readable number.
staticMode boolean false Suppress hover interactions and end-label HTML overlay for export/SSR contexts.
yScale "linear" | "log" "linear" Currently linear only; log is reserved for the FT covid chart battle-test and falls back with a warning.
Use with AI
LLM Prompt
Create a React component using Campos LineChart. Import LineChart from @withqwerty/campos-react, pass series as { id, label, points: { x, y }[] }, and opt in to trendlines / events when the story calls for them. Prefer xAxisLabel for the time axis and leave yAxisLabel empty when the unit is implied by the series labels.