# Choropleth Map

> Regions shaded by value in one hue, in steps, with hatching for regions with no data, a legend that filters, and arrow keys that move from region to region.

- Name: `choropleth-map`
- Status: beta
- Categories: charts
- File: the install writes `choropleth-map.tsx` to your `ui` alias, `@/components/ui` by default.
- Other registry items: `@arbokui/chart`, `@arbokui/skeleton`. The install adds them.
- Gallery: https://arbokui.com/components/choropleth-map
- Registry item: https://arbokui.com/r/choropleth-map.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/choropleth-map
   ```

## Use it for

- A value per country, state, or province, where where it is matters, like members by state or sales by country.
- Pass shape, a map already projected: { width, height, regions: \[{ id, name, d, c }\] }, with a title or aria-label.
- Pass values by region id, like { 'US-TX': 120 }. A region without a number is hatched and reads 'No data'.
- Pass steps to set where each shade starts, like \[10, 50, 100\] for four shades. By default the shades split the values into quarters.
- Pass onRegionSelect to make each region a button, and selected to outline the chosen one.
- This site builds its shapes into /maps: world.json for countries, and admin1/\<ID>.json for each country's regions. Copy the ones you need into your app, or build your own in the same shape.

## Avoid it for

- Exact numbers people must compare. Use BarChart or BreakdownList beside the map.
- Values that only follow area or population. Show a rate, like per 1,000 people, so big regions do not win by size.
- Streets, zooming, or panning. This map draws fixed shapes, not tiles.

## Props

- `shape`: `ChoroplethShape`. The map, already projected: { width, height, regions, outline?, frames?, dots? }. Each region is { id, name, d, c, dot? }, where d is an SVG path and c a point inside it.
- `values`: `Record<string, number | null>`. Each region's value, by region id.
- `steps`: `number[]`. Default `the quartiles of values`. Where each shade starts, lowest first. Three numbers make four shades.
- `valueFormat`: `Intl.NumberFormatOptions`. How values read, in the readout and the legend, like { style: 'percent' }.
- `selected`: `string | null`. The region outlined as chosen.
- `onRegionSelect`: `(id: string) => void`. Called on click, Enter, or Space. Makes each region a button with aria-pressed.
- `noDataText`: `string`. Default `"No data"`. What a region with no value reads.
- `size`: `"sm" | "md" | "lg"`. Default `"md"`. Height. The map keeps its own shape inside it.
- `loading`: `boolean`. Shows the regions as placeholders, or a placeholder box when there is no shape yet.
- `error`: `ReactNode`. Shows this message in place of the map. Pass onRetry for a retry button.
- `emptyText`: `ReactNode`. Default `"No regions to show"`. Shown when the shape has no regions.
- `title`: `ReactNode`. Names the map. Pass this, aria-label, or aria-labelledby.
- `locale`: `string`. Default `"en-US"`. The locale for numbers. The default keeps the server and the browser the same.
- `className`: `string`. Extra classes for the figure. '\[--choropleth-color:var(--chart-3)\]' sets the hue. It defaults to --chart-1.

## Accessibility

- The map is a group named by its title. Each region is named by its name and value, like 'Texas: 120'.
- The map is one Tab stop. Arrow keys move to the nearest region that way, and Home and End go to the first and last by name.
- With onRegionSelect, each region is a button with aria-pressed, and Enter or Space chooses it.
- No data is a hatch, not only a lighter shade, so it reads apart from low values without color.
- The legend steps are buttons. Hovering or focusing one shows only its regions. Pressing one keeps it on, with aria-pressed.
- In forced colors, the shades become steps of the text color, the hatch stays, and the focused region is outlined in Highlight.

## Examples

### Members by state

```tsx
import usa from "./maps/admin1/USA.json";

<ChoroplethMap title="Members by state" shape={usa} values={{ "US-TX": 120, "US-CA": 210 }} />
```

### Set steps and a format

```tsx
<ChoroplethMap
  aria-label="Turnout by prefecture"
  shape={japan}
  values={turnout}
  steps={[0.5, 0.55, 0.6]}
  valueFormat={{ style: "percent" }}
/>
```

### Choose a country

```tsx
<ChoroplethMap
  title="Clubs by country"
  shape={world}
  values={clubs}
  selected={country}
  onRegionSelect={setCountry}
/>
```
