Skip to main content

ChoroplethChart

Distributionchart

Region-shaded map for a measure that is defined per geographic area.

import { ChoroplethChart } from "@elabs-ai/components-charts";
Install
npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-charts

Skipping the @source line is the most common first failure: Tailwind does not scan node_modules, so every component renders unstyled. The one-time wiring

Prompt for your coding agent

Paste it into Claude Code, Cursor, Codex or any other coding agent. Text in [brackets] is yours to fill in.

Add the brand-ui ChoroplethChart chart (from @elabs-ai/components-charts) to this project.

1. Read https://elabs-ai.com/llms.txt first: it maps every package and the rules. If you can use MCP servers, connect https://elabs-ai.com/mcp and use its search, docs and tokens tools. If not, run the same lookups in the terminal: `npx -y @elabs-ai/components-cli search "<what you need>"` and `npx -y @elabs-ai/components-cli docs <Component>`.
2. Look ChoroplethChart up before writing code: `npx -y @elabs-ai/components-cli docs ChoroplethChart` prints its real props, variants, what it pairs with and what to avoid.
3. If @elabs-ai/components-charts is not installed yet: `pnpm add @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-charts` (or `npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-charts`). If this is the first brand-ui package in the project, wire it once: import `@elabs-ai/components-tokens/styles.css` plus the `themes/light.css` and `themes/dark.css` stylesheets in the CSS entry, add one Tailwind `@source` line per installed @elabs-ai package (Tailwind does not scan node_modules, so without it everything renders unstyled), and wrap the app root in `ThemeProvider` from `@elabs-ai/components-tokens`.
4. Use it here: [the screen or file, and what it should show]
5. Rules: use only @elabs-ai/components-* components and the semantic tokens — no raw colours, no raw font sizes, no arbitrary Tailwind values. Look up each component's real props with the docs tool before you use it; never guess a prop.
6. Done means: the typecheck passes, `npx -y @elabs-ai/components-cli audit src --strict` reports nothing, and you have opened the app and looked at every screen you touched in the light and the dark theme.

Use it for

  • a measure by geographic region

Avoid

  • there is no real geography — use a bar chart
  • Shading raw counts instead of a rate — area size becomes the story and the map lies.
  • A rainbow ramp for a sequential measure — use one ordered ramp so darker always means more.
  • Shipping it without a legend — a shaded region carries no value without the scale.

Works with

Pairs with

Examples

15 live examples

Loading

`status="loading"` (RM-185): a skeleton fills the same plot box the ready map would use, at every width, so nothing moves once the data lands.

Loading Scale Height Parity

Review fix4: `scale` set + `status="loading"` must never build the live key from data that has no real values yet — that key's own domain/step text is fabricated ("Colour scale: 4 steps from 0 to 1"), and it doesn't take up the same room the ready key will once real values land. Not a jsdom test (`aspect-ratio` doesn't compute a real pixel height there) — a real browser is the only way to prove the loading and ready roots agree.

Zoom Enabled

Zoom and pan enabled.

Accessible Name

Accessible name + keyboard navigation overlay. - The container gets `role="figure"` + `aria-label` + `aria-describedby` matching the pattern used by all other @elabs-ai/components-charts charts (issue #145). - `keyboardNav` adds a visually-hidden listbox so keyboard users can arrow-navigate through geographic features. Each item announces its region name and score value. Focus syncs to the SVG highlight. - Tab into the map → first feature is focused; ArrowRight / ArrowDown moves forward; ArrowLeft / ArrowUp moves back; Home / End jumps to first / last.

Data Table Fallback

Data-table fallback — the tabular equivalent of the map data. The chart renders normally; below it (visually) sits an accessible `<table>` that exposes every annotated data point to screen-reader + keyboard users. This is the standard non-visual fallback for SVG data visualisation (WCAG 1.1.1 text alternative) and gives keyboard users a structured way to scan all values without relying on the keyboard-nav overlay. In production, conditionally render the table (e.g. via a visually-hidden `sr-only` wrapper) or use ChartFrame's flip-to-table button (issue #116).

No-data hatch + top-5 labels (M1/M2)

`noDataFill="hatch"` + `labelTop={5}` (M1/M2) — Alaska and Hawaii carry no `value` and render with a diagonal `--chart-grid` hatch instead of a flat palette fill; the five largest states by population (California, Texas, Florida, New York, Pennsylvania) get an inline halo'd name label at their centroid.

No Data Muted

`noDataFill="muted"` — the flat `var(--muted)` alternative to the hatch pattern.

Stepped quantile scale with titled legend and notes

The “Europe cooling” recipe: an 11-class quantile scale, a titled ramp with words instead of numbers, and six notes. At the narrow tier the legend moves below the map, the notes become a numbered key, and the map keeps its 16:9 aspect.

Fit to data, regions without data hidden

`fitToData` frames the 12 states that carry data and `hideNoData` removes the rest from the DOM, so the map is about the data, not the country.

Proportional symbols with a size key

Proportional symbols at region centroids: the AREA encodes the value, so a 4× value draws a 2× radius. On a plot narrower than 700 px every symbol shrinks by `sqrt(width / 700)`.

Zoom buttons with keyboard reset

Zoom buttons: real `<button>`s outside the map's `<svg>`, so every zoom the wheel or a drag can do is reachable from the keyboard. Reset returns to the fitted view.

Locator inset and place labels

A locator inset (the visible extent on a globe) and region names laid out by the label solver — at most 30, colliding ones dropped, none at narrow (the dropped names stay in the text for assistive technology).

Categories with a pattern overlay

`palette: "categorical"` colours by a text field and keys it with swatches; `overlayBy` stripes the regions whose `estimated` field is set, so the flag reads in greyscale too.

Empty

No region carries data and `hideNoData` is on: an empty state, never a blank frame.

API

ChoroplethChart

PropTypeDescription
messagesChartMessagesmessages group (RM-187): this chart's own words, keyed by the ui catalogue's `charts.*` message keys. A key set here wins over the `LocaleProvider`; every other key reads the catalogue as before.
datarequiredFeatureCollection<Geometry, ChoroplethFeatureProperties>GeoJSON FeatureCollection data
marginnumber | Partial<Margin>Chart margins: one number for every side, or per side.
animationDurationnumberAnimation duration in milliseconds. Default: 800
enterTransitionTransitionMotion enter transition (spring or cubic-bezier tween).
revealSignaturestringSignature of motion URL state — triggers enter replay when it changes.
aspectRatiostringAspect ratio as "width / height". Default: "16 / 9"
plotHeightResponsive<ChartPlotHeight>The plot's own height (ADR 0039): px, or `{ aspect }` (width ÷ height), optionally per breakpoint. Wins over `aspectRatio`, which stays an alias.
scalenumber | ChoroplethScaleSpecThe COLOUR scale (RM-124): `{ key, type: "continuous" | "stepped", method?, steps?, domain?, palette? }`, resolved by `colorScaleFor` over every feature's `properties[key]` (default key `"value"`) into the chart token ramps. `ChoroplethFeature getFeatureColor` / `fill` still override it. Deprecated form: a NUMBER is the projection scale, kept as an alias of `projectionScale` (removed in 7.0.0).
projectionScalenumberProjection scale. If not provided, auto-calculated based on width (or solved by `fitToData`).
legendboolean | ChoroplethLegendConfigThe colour key (RM-118 `RampLegend`; swatches for a categorical palette), plus the `SizeLegend` of `symbols` and the `overlayBy` key. Unset: shown with a `scale` or `symbols`, but hidden at the narrow tier; `true` or a config always shows it. `position` defaults to `{ base: "bottom-left", narrow: "below" }`. `false` hides it.
fitToDataChoroplethFitToDataFrame the map on the regions that carry data (`scale.key`, default `"value"`): the projection's scale / translate are solved so they fill the plot, minus `padding`. The other regions stay, cropped by the plot edge, unless `hideNoData` is set. Wins over `projectionScale` / `translate`.
hideNoDatabooleanRemove every region without data from the map (and the DOM). All gone → the empty state.
insetChoroplethInsetConfigA locator mini map in a corner, outlining the visible extent.
labelsChoroplethPlaceLabelsConfigRegion names at their centroids (at most 30), placed through the shared label collision engine; not painted at the narrow tier. Dropped names are restated for screen readers.
overlayByChoroplethOverlayConfigStripes over every region whose `key` holds a category (one direction per category).
symbolsChoroplethSymbolsConfigProportional symbols at the feature centroids (or `points`), with their own size key.
zoomControlsboolean | Partial<ChoroplethZoomLabels>`+` / `−` / reset buttons (real buttons, keyboard-operable) in the top corner; turns zoom on. Pass an object to translate their names.
annotationsreadonly ChartAnnotation[]Text annotations at `x` = longitude, `y` = latitude (RM-111). At the narrow tier each note becomes a numbered marker listed under the map.
emptyChartEmptyStateWhat the chart shows when `hideNoData` left no region: a `title`, a supporting `message` and an optional `action` below it. Each key you leave out keeps its default. Default `{ title: "No data", message: "No region has data to map." }`.
emptyTitlestringTitle of the empty state (`hideNoData` left no region). @deprecated Since 6.0.0, use `empty.title`. Removed in 7.0.0.
emptyMessagestringMessage of the empty state. @deprecated Since 6.0.0, use `empty.message`. Removed in 7.0.0.
center[number, number]Center coordinates [longitude, latitude]. Default: [0, 20]
translate[number, number]Translate offset [x, y]. If not provided, auto-calculated to center
zoombooleanEnable zoom and pan. Default: false. `zoomControls` alone still turns it on.
zoomEnabledbooleanEnable zoom and pan. @deprecated Since 6.0.0, use `zoom`. Removed in 7.0.0.
zoomMinnumberMinimum zoom scale. Default: 0.5
zoomMaxnumberMaximum zoom scale. Default: 4
initialZoomTransformMatrixInitial zoom transform
classNamestringAdditional class name for the container
statusChartStatusLoading vs ready (RM-185). `"loading"` shows a skeleton in the plot box the chart will fill, with one polite status message, until the data is ready. Default: `"ready"`.
childrenrequiredReactNodeChild components (ChoroplethFeature, ChoroplethGraticule, ChoroplethTooltip)
accessibleLabelChartA11yProps["accessibleLabel"]Accessible name for the chart region (role="figure"). Announced by AT on focus. Example: "World market share choropleth map"
accessibleDescriptionChartA11yProps["accessibleDescription"]Supplemental description (region count, value range, etc.). Rendered as a visually-hidden span associated via aria-describedby.
keyboardNavChoroplethKeyboardNavPropsWhen provided, a visually-hidden keyboard-navigation overlay is rendered so keyboard users can arrow-navigate through geographic features. Pass the same props accepted by ChoroplethKeyboardNav (getFeatureName, getFeatureValue, valueLabel, navLabel).
paletteChartPaletteColour ramp for features drawn without a colour scale (RM-186): five colours through `resolvePalette`, cycled. A colour scale, `fill` or `getFeatureColor` still wins. Unset: `--chart-1` … `--chart-5`, as before.

Also accepts: FrameSizeGroupProps, ChartStateGroupProps

ChoroplethGraticule

PropTypeDescription
strokestringStroke color for graticule lines. Default: a faint, theme-aware foreground tint.
strokeWidthnumberStroke width for graticule lines. Default: 0.5
step[number, number]Step intervals for graticule lines [longitude, latitude] in degrees. Default: [10, 10]

ChoroplethTooltip

PropTypeDescription
content(props: { feature: ChoroplethFeature; index: number }) => React.ReactNodeCustom content renderer for feature tooltips
formatValue(value: number) => stringValue formatter function
getFeatureName(feature: ChoroplethFeature, index: number) => stringGet the display name for a feature. Default: uses feature.properties.name
getFeatureValue(feature: ChoroplethFeature, index: number) => number | undefinedGet the value for a feature (for display in tooltip)
valueLabelstringLabel for the value row. Default: "Value"
classNamestringCustom class name