BumpChart
Rank-over-time chart for league positions, form tables, and other discrete ranking progressions. Use it when the story is movement across ranked timepoints, not raw values on a continuous axis. Hero fixture: syntheticized Premier League 2019/20 title-race progression derived from real standings snapshots.
Canonical behaviors.
No ranking data. The chart stays explicit instead of faking a line.
Minimal valid bump chart: only a few teams and a few matchweeks.
Highlight a subset of teams and let the rest fall into the background.
More teams and more overlap. This is the main readability stress case for labels and line weight.
Straight segments instead of smooth curves when the page wants a more literal step between timepoints.
Useful when the chart needs stronger identity at both edges.
Team logos can sit in the end labels without changing the underlying chart model. This remains a browser-only seam, not part of ExportFrameSpec.
Liverpool
Man City
Man Utd
Chelsea
Spurs
ArsenalWhen markers are hidden, the trend lines stay keyboard-focusable so tooltip access does not disappear.
Stress case for truncation, edge spacing, and mixed-script rendering.
Static mode swaps to deterministic SVG labels and keeps the chart readable without hover.
ThemeProvider can restyle the chart without changing the row model or ordering semantics.
Composition patterns.
Use the shared note seam for ranking-source and sample context instead of duplicating prose around the card.
Shared concerns.
Choose BumpChart
Use BumpChart when the y-axis is an ordinal rank. If the story is raw x/y values, use a Cartesian chart instead.
Data Contract
Rows should already be grouped into one point per team per timepoint. The component does not aggregate standings for you.
Label Strategy
End labels are the default identity surface. Highlighting and team colours should support that read, not replace it.
Accessibility
Markers expose tooltip content on hover and focus. If markers are hidden, the line layer keeps a keyboard-focusable fallback so the trend is still inspectable.
Export / Static
The stable export surface supports constant-only style props and deterministic SVG labels. Custom end-label renderers and team-logo HTML labels sit outside that contract.
Responsive Behavior
BumpChart is fundamentally a wide ranking chart. On narrow widths the line read survives first; long edge labels and extra annotation should degrade before the rank trajectories do.
Composition
This chart is strongest as a standalone analytical panel, but methodology notes can live inside the shared chart frame rather than being rebuilt in page chrome.
Width pressure.
The narrow view should preserve the rank trajectories first and let labels do the degrading.
Wide layouts keep end labels, marker spacing, and highlight contrast legible with less compromise.
Best-practice examples.
Minimal usage
Pass one row per team per timepoint. The component handles interpolation, markers, and end labels.
import { BumpChart } from "@withqwerty/campos-react";
export function LeagueProgression({ rows }) {
return <BumpChart rows={rows} />;
}
Recipe-driven race highlight
Use named bump-chart recipes for the common ranking-tracker modes, then pass the actual highlighted teams and club colours from your data layer.
import { BumpChart, bumpChartRecipes } from "@withqwerty/campos-react";
export function TitleRaceChart({ rows }) {
return (
<BumpChart
rows={rows}
highlightTeams={["LIV", "MCI", "ARS"]}
teamColors={{ LIV: "#c8102e", MCI: "#6cabdd", ARS: "#ef4444" }}
rankDomain={[1, 20]}
{...bumpChartRecipes.focusRace.props}
/>
);
}
Public surface.
| Prop | Type | Default | Description |
|---|---|---|---|
rows | readonly BumpChartRow[] | required | Array of { team, timepoint, rank } objects, one row per team per timepoint. |
highlightTeams | readonly string[] | undefined | Teams to emphasize; all others fade to backgroundOpacity. |
interpolation | "smooth" | "linear" | "smooth" | Curve style between discrete timepoints. |
showMarkers | boolean | true | Show dot markers at each timepoint. |
showEndLabels | boolean | true | Show team labels at the right edge. |
showStartLabels | boolean | false | Show team labels at the left edge. |
showGridLines | boolean | true | Show horizontal grid lines at each rank position. |
rankDomain | readonly [number, number] | auto from data | Explicit y-axis range, for example [1, 20] for a full league. |
teamColors | Record<string, string> | auto palette | Map team identifiers to explicit colours. |
timepointLabel | string | "Matchweek" | X-axis label text. |
rankLabel | string | "Position" | Y-axis label text. |
markerRadius | number | 3 | Radius of data-point marker dots in px. |
backgroundOpacity | number | 0.15 | Opacity for non-highlighted team lines. |
teamLogos | Record<string, string> | — | Optional logo map for the built-in HTML end labels. Useful in browser docs; intentionally outside the stable export contract. |
renderEndLabel | (props: EndLabelRenderProps) => ReactNode | — | Advanced custom end-label renderer. Use when badge or logo composition matters more than plain text. |
methodologyNotes | ChartMethodologyNotes | — | Shared chart-frame note seam for sample, eligibility, and methodological context. |
staticMode | boolean | false | Switches to the deterministic SVG label path used for export-safe, no-hover contexts. |
lines | BumpChartLinesStyle | — | First-class styling surface for team trend lines. |
points | BumpChartPointsStyle | — | First-class styling surface for rank markers. |
labels | BumpChartLabelsStyle | — | First-class styling surface for start and end labels. |
guides | BumpChartGuidesStyle | — | First-class styling surface for horizontal rank guides. |
`staticMode` is the export-safe path for the live component. `teamLogos` and `renderEndLabel` are intentionally browser-only seams and are rejected from the current `ExportFrameSpec` contract.
Create a React component using Campos BumpChart. Import BumpChart and bumpChartRecipes from @withqwerty/campos-react, keep row shaping outside the component, show the smallest good usage first, then one recipe-driven highlighted race or linear ranking-tracker variant.