import { ChoroplethChart } from "@elabs-ai/components-charts";npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-chartsPaste 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
Used inside
Pairs with
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
| Prop | Type | Description |
|---|---|---|
messages | ChartMessages | messages 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. |
datarequired | FeatureCollection<Geometry, ChoroplethFeatureProperties> | GeoJSON FeatureCollection data |
margin | number | Partial<Margin> | Chart margins: one number for every side, or per side. |
animationDuration | number | Animation duration in milliseconds. Default: 800 |
enterTransition | Transition | Motion enter transition (spring or cubic-bezier tween). |
revealSignature | string | Signature of motion URL state — triggers enter replay when it changes. |
aspectRatio | string | Aspect ratio as "width / height". Default: "16 / 9" |
plotHeight | Responsive<ChartPlotHeight> | The plot's own height (ADR 0039): px, or `{ aspect }` (width ÷ height), optionally per breakpoint. Wins over `aspectRatio`, which stays an alias. |
scale | number | ChoroplethScaleSpec | The 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). |
projectionScale | number | Projection scale. If not provided, auto-calculated based on width (or solved by `fitToData`). |
legend | boolean | ChoroplethLegendConfig | The 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. |
fitToData | ChoroplethFitToData | Frame 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`. |
hideNoData | boolean | Remove every region without data from the map (and the DOM). All gone → the empty state. |
inset | ChoroplethInsetConfig | A locator mini map in a corner, outlining the visible extent. |
labels | ChoroplethPlaceLabelsConfig | Region 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. |
overlayBy | ChoroplethOverlayConfig | Stripes over every region whose `key` holds a category (one direction per category). |
symbols | ChoroplethSymbolsConfig | Proportional symbols at the feature centroids (or `points`), with their own size key. |
zoomControls | boolean | Partial<ChoroplethZoomLabels> | `+` / `−` / reset buttons (real buttons, keyboard-operable) in the top corner; turns zoom on. Pass an object to translate their names. |
annotations | readonly ChartAnnotation[] | Text annotations at `x` = longitude, `y` = latitude (RM-111). At the narrow tier each note becomes a numbered marker listed under the map. |
empty | ChartEmptyState | What 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." }`. |
emptyTitle | string | Title of the empty state (`hideNoData` left no region). @deprecated Since 6.0.0, use `empty.title`. Removed in 7.0.0. |
emptyMessage | string | Message 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 |
zoom | boolean | Enable zoom and pan. Default: false. `zoomControls` alone still turns it on. |
zoomEnabled | boolean | Enable zoom and pan. @deprecated Since 6.0.0, use `zoom`. Removed in 7.0.0. |
zoomMin | number | Minimum zoom scale. Default: 0.5 |
zoomMax | number | Maximum zoom scale. Default: 4 |
initialZoom | TransformMatrix | Initial zoom transform |
className | string | Additional class name for the container |
status | ChartStatus | Loading 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"`. |
childrenrequired | ReactNode | Child components (ChoroplethFeature, ChoroplethGraticule, ChoroplethTooltip) |
accessibleLabel | ChartA11yProps["accessibleLabel"] | Accessible name for the chart region (role="figure"). Announced by AT on focus. Example: "World market share choropleth map" |
accessibleDescription | ChartA11yProps["accessibleDescription"] | Supplemental description (region count, value range, etc.). Rendered as a visually-hidden span associated via aria-describedby. |
keyboardNav | ChoroplethKeyboardNavProps | When 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). |
palette | ChartPalette | Colour 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. |
ChoroplethGraticule
| Prop | Type | Description |
|---|---|---|
stroke | string | Stroke color for graticule lines. Default: a faint, theme-aware foreground tint. |
strokeWidth | number | Stroke width for graticule lines. Default: 0.5 |
step | [number, number] | Step intervals for graticule lines [longitude, latitude] in degrees. Default: [10, 10] |
ChoroplethTooltip
| Prop | Type | Description |
|---|---|---|
content | (props: { feature: ChoroplethFeature; index: number }) => React.ReactNode | Custom content renderer for feature tooltips |
formatValue | (value: number) => string | Value formatter function |
getFeatureName | (feature: ChoroplethFeature, index: number) => string | Get the display name for a feature. Default: uses feature.properties.name |
getFeatureValue | (feature: ChoroplethFeature, index: number) => number | undefined | Get the value for a feature (for display in tooltip) |
valueLabel | string | Label for the value row. Default: "Value" |
className | string | Custom class name |