Skip to content
  • System
  • Light
  • Dark
  • High contrast

GeoChart

Regions coloured by value using a three-colour scale (red → amber → green).

import { GeoChart } from '@eekodigital/raster/geo';
import world from 'world-atlas/countries-110m.json';

<GeoChart
topology={world}
data={[
  { id: '826', value: 95, label: 'United Kingdom' },
  { id: '840', value: 65, label: 'United States' },
  { id: '392', value: 85, label: 'Japan' },
]}
colorScale={['var(--demo-bad)', 'var(--demo-warn)', 'var(--demo-good)']}
title="Compliance by country"
/>

Bubble markers at lat/lon coordinates overlaid on the choropleth.

<GeoChart
topology={world}
data={data}
markers={[
  { lat: 51.5, lon: -0.1, size: 8, label: 'London' },
  { lat: 48.9, lon: 2.3, size: 6, label: 'Paris' },
  { lat: 40.7, lon: -74.0, size: 7, label: 'New York' },
]}
title="Compliance with office markers"
/>

GeoChart does not bundle any map data. Install world-atlas for world country boundaries, or provide your own TopoJSON data.

"mercator" (default) — most recognisable, distorts area at poles.

"equirectangular" — honest area representation, flat appearance.

Custom function: (lon, lat) => [x, y] where x/y are 0-1 normalised.

Pass a filter array of feature IDs to show only specific regions:

<GeoChart topology={world} filter={["826", "372"]} data={ukData} title="UK and Ireland" />
  • A role="figure" named by the visible title and described by a generated summary (chart type, series and point counts, range).
  • The SVG is a role="group" with aria-roledescription="chart"; no graphics-* roles.
  • Regions and markers are two role="group"s. Every region is focusable, labelled {name}: {value}, 3 of 177, or {name}: No data when it has none. Markers are labelled Markers, {label}, 1 of 4. With onSelect, selectedIndex or a click handler, marks are role="button" with aria-pressed; otherwise they’re static role="img".
  • The data table lists every region (including those with no data) and every marker.
  • Escape (inside the chart only) clears the selection and announces it in a polite live region; it doesn’t close a surrounding dialog.
  • Animations stop under prefers-reduced-motion. In forced-colours mode marks use system colours, told apart by dash pattern and marker shape.
Key Action
← / → Previous / next region or marker
Home / End First / last
PageUp / PageDown Back / forward 10
↑ / ↓ Switch between regions and markers
Tab Leave the map
Enter / Space Toggle selection (interactive marks)
Escape Hide the tooltip and clear selection

See the Accessibility guide for the shared structure, the labels prop and screen-reader testing.

PropTypeDefaultDescription
topologyGeoTopology—

Required. TopoJSON, e.g. world-atlas.

objectNamestringfirst objectTopology object to draw.
dataGeoRegionDatum[][]

{ id, value, label? } per region.

colorScalestring[]series 1 rampColours from low to high.
markersGeoMarker[][]

{ lat, lon, label, value?, size?, color? }.

projection“mercator” | “equirectangular” | fn“mercator”Map projection.
filterstring[]—Only draw these region ids.
legendLabelstring—Colour-scale legend title.
formatValue(value: number) => stringIntl.NumberFormat

Formats values in ticks, marks and the table. Defaults to Intl.NumberFormat(labels.locale).

heightnumber—Plot height in px.
aspectRationumber16 / 9Width ÷ height. The map fills its container’s width.
onRegionClick(datum, id) => void—Makes regions buttons.
onMarkerClick(marker, index) => void—Makes markers buttons.
selectedIndex{ region } | { marker } | null—Controlled selection.
onSelect(selection | null) => void—Makes regions and markers buttons.
titlestring—Required. Visible title: names the figure and captions the data table.
hideTitlebooleanfalseHide the title visually. It still names the chart for assistive technology.
labelsPartial<ChartLabels>English

Generated strings and the number locale. See Accessibility.

dataTable“disclosure” | “visually-hidden”“disclosure”How the data table is offered.
exportRefRef<ChartExportHandle>—

SVG/PNG export. See Exporting charts.

classNamestring—Class on the figure.