Component

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.

13579111315171921232527293133353738Matchweek12345678910Position
Liverpool
Man City
Man Utd
Stories

Canonical behaviors.

Empty State

No ranking data. The chart stays explicit instead of faking a line.

No ranking data
Sparse Timepoints

Minimal valid bump chart: only a few teams and a few matchweeks.

123Matchweek12345678910Position
Liverpool
Man City
Man Utd
Highlighted Race

Highlight a subset of teams and let the rest fall into the background.

13579111315171921232527293133353738Matchweek123456789101112Position
Liverpool
Man City
Man Utd
Dense Field

More teams and more overlap. This is the main readability stress case for labels and line weight.

1234567891011121314151617181920Matchweek12345678910Position
Liverpool
Man City
Leicester
Linear Interpolation

Straight segments instead of smooth curves when the page wants a more literal step between timepoints.

13579111315171921232527293133353738Matchweek12345678910Position
Liverpool
Man City
Man Utd
Start And End Labels

Useful when the chart needs stronger identity at both edges.

13579111315171921232527293133353738Matchweek12345678910PositionLiverpoolMan CityMan Utd
Liverpool
Man City
Man Utd
Logo Labels

Team logos can sit in the end labels without changing the underlying chart model. This remains a browser-only seam, not part of ExportFrameSpec.

13579111315171921232527293133353738Matchweek123456789101112Position
Liverpool
Man City
Man Utd
Chelsea
Spurs
Arsenal
Line-Only Interaction

When markers are hidden, the trend lines stay keyboard-focusable so tooltip access does not disappear.

13579111315171921232527293133353738Matchweek12345678910Position
Liverpool
Man City
Man Utd
Long And Multilingual Labels

Stress case for truncation, edge spacing, and mixed-script rendering.

12345678910Matchweek12345678910Position
Athletic Cl…
横浜F・マリノス
Borussia Mö…
Static Export Mode

Static mode swaps to deterministic SVG labels and keeps the chart readable without hover.

13579111315171921232527293133353738Matchweek12345678910PositionLiverpoolMan CityMan Utd
Dark Theme

ThemeProvider can restyle the chart without changing the row model or ordering semantics.

13579111315171921232527293133353738Matchweek12345678910Position
Liverpool
Man City
Man Utd
Recipes

Composition patterns.

Methodology Notes

Use the shared note seam for ranking-source and sample context instead of duplicating prose around the card.

12345678910Matchweek12345678910Position
Liverpool
Man City
Sample: first 10 matchweeks only. Values in the tooltip are cumulative league points, not a second plotted axis.
Cross-cutting

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.

Responsive

Width pressure.

Compact Container

The narrow view should preserve the rank trajectories first and let labels do the degrading.

13579111315171921232527293133353738Matchweek12345678910Position
Liverpool
Man City
Man Utd
Wide Analytical Panel

Wide layouts keep end labels, marker spacing, and highlight contrast legible with less compromise.

1234567891011121314151617181920Matchweek12345678910Position
Liverpool
Man City
Leicester
Usage

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}
    />
  );
}
                  
API

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.

Use with AI
LLM Prompt
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.