# Choropleth Explorer

> A world map of one measure. Choose a country to see its states, provinces, or regions, with a breadcrumb back, a country search, a ranked list, and a tab per measure.

- Name: `choropleth-explorer`
- Status: beta
- Categories: dashboard, map, geography, charts
- Files: the install writes `choropleth-explorer.tsx`, and any part files named `choropleth-explorer-*.tsx`, to your `components` alias, `@/components` by default. Edit them freely. They are yours.
- Other registry items: `@txbrendan/breadcrumb`, `@txbrendan/breakdown-list`, `@txbrendan/card`, `@txbrendan/chart`, `@txbrendan/choropleth-map`, `@txbrendan/combobox`, `@txbrendan/tabs`. The install adds them.
- Gallery: https://txbrendan.dev/blocks/choropleth-explorer
- Registry item: https://txbrendan.dev/r/choropleth-explorer.json

## Install

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

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

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

   ```json
   {
     "registries": {
       "@txbrendan": "https://txbrendan.dev/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@txbrendan` in a public list that txbrendan/ui 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 @txbrendan/theme
   ```

3. Add the block. It also adds every component it uses:

   ```bash
   npx shadcn@latest add @txbrendan/choropleth-explorer
   ```

## Use it for

- A measure by place, where people start with the world and look closer at one country, like members, sales, or sign-ups.
- Pass metrics, each with values for countries and their regions together, like { USA: 340, 'US-TX': 31 }. Countries use ISO 3166-1 alpha-3 codes, and regions ISO 3166-2 codes, where the place has one.
- The maps load from src, '/maps' by default: world.json, then admin1/\<ID>.json for the country chosen. This site serves them. In your app, copy the files into public/maps, or pass loadShape.
- The line under the map says how many regions there are, how many have data, and that states or provinces are as deep as the maps go.
- Pass country and onCountryChange to keep the chosen country in the URL.

## Avoid it for

- Cities, counties, or streets. These maps stop at states and provinces.
- One country only. Use ChoroplethMap with that country's shape.
- Exact comparisons across many places. Use a table, sorted by the measure.

## Props

- `metrics`: `{ id: string; label: string; values: Record<string, number | null>; valueFormat?: Intl.NumberFormatOptions }[]`. One tab per metric. Values hold countries and their regions together, by id.
- `title`: `ReactNode`. The block's heading. It also names the section.
- `src`: `string`. Default `"/maps"`. Where world.json and admin1/\<ID>.json are.
- `loadShape`: `(id: string) => Promise<ExplorerShape>`. Loads a map yourself, by 'world' or a country id, in place of src. Define it outside the component, so each map loads once.
- `country`: `string | null`. The country shown, by id. null shows the world. Use with onCountryChange.
- `defaultCountry`: `string | null`. Default `null`. The country shown first, when you do not control it.
- `onCountryChange`: `(country: string | null) => void`. Called when someone chooses a country or goes back to the world.
- `loading`: `boolean`. Default `false`. Shows placeholders while the metrics load.
- `emptyText`: `ReactNode`. Default `"No data to map yet."`. Shown when there are no metrics.
- `top`: `number`. Default `8`. How many places the ranked list shows.
- `className`: `string`. Extra classes on the section, which holds the container query.

## Accessibility

- The section is named by its title. The breadcrumb is a nav named 'Map level', and World is a button while a country shows.
- Every country has its own option in the search, so a country too small to point at is still one choice away.
- The map is one Tab stop, and arrow keys move between places. On the world map, Enter opens the country. In a country, Enter marks a region.
- A status line says each new map as it loads, like 'Members, Japan: 47 prefectures'.
- The ranked list repeats the top values as text, so nobody has to read them from shades.

## Examples

### Members by country and region

```tsx
<ChoroplethExplorer
  title="Members"
  metrics={[
    { id: "members", label: "Members", values: { USA: 340, "US-TX": 31, JPN: 120, "JP-13": 40 } },
    { id: "growth", label: "Growth", values: growth, valueFormat: { style: "percent" } },
  ]}
/>
```

### Keep the country in the URL

```tsx
<ChoroplethExplorer metrics={metrics} country={params.country ?? null} onCountryChange={setCountry} />
```
