PitchKit
Guides

Responsive

Pitches fill their container by default; fixed pixels are the opt-out.

Responsiveness isn't a prop — it's the default. A <Pitch> fills its container's width, keeps the pitch's own aspect ratio, and re-renders through a ResizeObserver as the container changes. Sizing a pitch means sizing its parent, like an <img>:

<div style={{ maxWidth: "40rem" }}>
  <Pitch type="statsbomb">…</Pitch>
</div>

First paint and SSR

Before the first client-side measurement (including on the server, where there's nothing to measure), the pitch renders at a nominal size with the correct aspect ratio — so server-rendered output is never distorted, and the post-hydration refinement only adjusts pixel scale, not shape. No flicker, no placeholder box.

The aspect ratio tracks what's actually shown: a crop to the attacking half reserves space for half a pitch, not a whole one.

Fixed size: the opt-out

Pass both width and height to pin exact pixels — for image export, fixed-layout embeds, or canvas work:

<Pitch type="statsbomb" width={640} height={427}>…</Pitch>

The heatmap caveat

<Heatmap> paints to a <canvas>, which needs real pixel dimensions up front — it can't lean on the SVG's responsive viewBox. Use a fixed-size pitch, or measure your own container and pass the result down (the same technique <Pitch> uses internally):

const containerRef = useRef<HTMLDivElement>(null);
const [width, setWidth] = useState(480);

useEffect(() => {
  const el = containerRef.current;
  if (!el) return;
  const observer = new ResizeObserver((entries) => {
    const entry = entries[0];
    if (entry) setWidth(entry.contentRect.width);
  });
  observer.observe(el);
  return () => observer.disconnect();
}, []);

return (
  <div ref={containerRef}>
    <Pitch type="statsbomb" width={width} height={Math.round(width / (120 / 80))}>
      <Heatmap data={events} x={(e) => e.x} y={(e) => e.y} binsX={12} binsY={8} />
    </Pitch>
  </div>
);

Every heatmap example on this site (see the gallery) uses this pattern — open one and copy it.

On this page