Theming
CSS variables only — set once, dark mode for free, override per chart.
PitchKit's theming is CSS variables only — the same mechanism shadcn/ui uses internally.
There are no JS theme objects and no per-instance colour props to thread through: set a
variable once in your global stylesheet and every <Pitch> picks it up through the cascade.
The variables
| Variable | Controls | Default |
|---|---|---|
--pitch-surface | Grass fill | #1a472a |
--pitch-stripe | Mow-stripe overlay | rgba(255, 255, 255, 0.04) |
--pitch-lines | Pitch markings; <Annotate> text; <Voronoi> cell edges | rgba(255, 255, 255, 0.8) |
--pitch-line-width | Marking stroke width | 1.5 |
--pitch-marker-primary | Default mark colour (<Scatter>, <Arrows>, <Comet>…) | #3b82f6 |
--pitch-marker-goal | <GoalAngle> wedge fill | #f97316 |
--pitch-tooltip-bg | Tooltip background | rgba(17, 17, 17, 0.92) |
--pitch-tooltip-color | Tooltip text | #fff |
Goal view variables
<GoalView> reads three more, and draws its ground and markings
with the pitch's own --pitch-surface, --pitch-lines and --pitch-line-width, so a themed pitch
and goal view match.
| Variable | Controls | Default |
|---|---|---|
--pitch-goal-backdrop | Everything behind the goal, the label boxes and the ring on shots | #0f2a19 |
--pitch-goal-net | The net | rgba(255, 255, 255, 0.18) |
--pitch-goal-frame | Posts and crossbar | #ffffff |
Player avatar variables
<PlayerAvatar> reads twelve more, and draws its cards with the
--pitch-card-yellow and --pitch-card-red below.
| Variable | Controls | Default |
|---|---|---|
--pitch-avatar-size | Photo diameter | Scales with the pitch |
--pitch-avatar-bg | Behind the photo and the initials | #d4d8dd |
--pitch-avatar-ring | The ring around the photo | #ffffff |
--pitch-avatar-text | The name | #ffffff |
--pitch-avatar-muted | The shirt number | rgba(255, 255, 255, 0.7) |
--pitch-avatar-icon | The goal and assist icons and counts | #111827 |
--pitch-avatar-icon-halo | The thin edge that lifts icons off the grass | rgba(255, 255, 255, 0.9) |
--pitch-avatar-ball | The ball's light panels | #ffffff |
--pitch-avatar-initials | The initials when there is no photo | #1f2937 |
--pitch-sub-on | The square, for a player who came on | #22c55e |
--pitch-sub-off | The square, for a player who went off | #ef4444 |
--pitch-sub-arrow | The arrow inside the square | #ffffff |
Chart variables
The charts read a second set. They are not the pitch's colours: a chart has no pitch, so these are meant to match the surface behind it, and most apps will set a light and a dark value.
| Variable | Controls | Default |
|---|---|---|
--pitch-series-1 … -6 | Series lines and bars, by position. <MomentumChart> uses 1 (home) and 2 (away) | #3b82f6, #eb6834, #1baf7a, #eda100, #e87ba4, #008300 |
--pitch-chart-surface | The ring around markers and the backing behind icons; set it to whatever is behind the chart | #ffffff |
--pitch-chart-text | Values, labels, legends | #12170f |
--pitch-chart-muted | Tick labels | #7b8474 |
--pitch-chart-accent | Controls the chart draws, such as the radar's Back button | #15803d |
--pitch-chart-accent-text | Text on those controls | #ffffff |
--pitch-axis | Baselines, period rules, the zero line | #c6cebc |
--pitch-grid | Gridlines and panel backgrounds | #e5eade |
--pitch-card-yellow | Yellow cards on a chart and on <PlayerAvatar> | #facc15 |
--pitch-card-red | Red cards and own goals on a chart, and red cards on <PlayerAvatar> | #ef4444 |
Charts that overlay series, like the radar, read best with up to three: past that, no palette keeps every pair distinguishable.
A yellow card is under 1.5:1 against white, so on a light surface darken --pitch-card-yellow.
Each chart's page lists the variables it reads.
/* globals.css */
:root {
--pitch-surface: #1a472a;
--pitch-lines: rgba(255, 255, 255, 0.8);
--pitch-marker-primary: #3b82f6;
}Every variable has a built-in fallback, so nothing is required — an unthemed <Pitch>
still renders sensibly.
Dark mode
Because it's plain CSS, dark mode is a second override behind whatever convention your app
already uses — a class, a media query, a data-theme attribute:
.dark {
--pitch-surface: #0b1712;
--pitch-lines: rgba(255, 255, 255, 0.35);
}No PitchKit configuration involved. This site's own examples work exactly this way.
Per-chart overrides
Variables cascade, so scoping an override to one chart is just a wrapper element:
<div style={{ "--pitch-surface": "#101418" } as React.CSSProperties}>
<Pitch type="statsbomb">{/* this one renders dark */}</Pitch>
</div>Structure vs colour
The appearance prop is deliberately separate from theming: it toggles which shapes get
painted (grass stripes, goal style), never colours.
<Pitch type="statsbomb" appearance={{ stripes: true, goalType: "box" }} />Individual marks
Colour accessors (fill, stroke, color) always win over the themed default for the
marks you pass them to — theming sets the baseline, accessors express data. For styling
marks with utility classes instead, see
Tailwind, which covers className, the
data-pitchkit-* attribute escape hatch, and the @utility recipe for the pitch
background.