Choropleth Chart

A composable geographic map chart for visualizing data across regions with interactive tooltips, zoom controls, and pattern support

Preview

Loading map data...

Installation

pnpm dlx shadcn@latest add https://ui.bklit.com/r/choropleth-chart.json

Usage

The Choropleth Chart uses a composable API similar to other charts. Build maps by combining components:

import { ChoroplethChart, ChoroplethFeatureComponent, ChoroplethGraticule, ChoroplethTooltip } from "@bklitui/ui/charts";
import * as topojson from "topojson-client";

// Load your GeoJSON data (from TopoJSON or direct GeoJSON)
const geojson = topojson.feature(topology, topology.objects.countries);

export default function WorldMap() {
  return (
    <ChoroplethChart data={geojson} aspectRatio="16 / 9">
      <ChoroplethGraticule />
      <ChoroplethFeatureComponent fill="var(--chart-1)" />
      <ChoroplethTooltip />
    </ChoroplethChart>
  );
}

Components

ChoroplethChart

The root component that sets up the Mercator projection and provides context to children.

PropTypeDefaultDescription
dataFeatureCollectionrequiredGeoJSON FeatureCollection with geographic features
marginPartial<Margin>{ top: 0, right: 0, bottom: 0, left: 0 }Chart margins
animationDurationnumber800Animation duration in ms
aspectRatiostring"16 / 9"CSS aspect ratio
scalenumberautoProjection scale (auto-calculated from width if not set)
center[number, number][0, 20]Center coordinates [longitude, latitude]
translate[number, number]autoTranslate offset [x, y]
zoomEnabledbooleanfalseEnable zoom and pan interactions
zoomMinnumber0.5Minimum zoom scale
zoomMaxnumber4Maximum zoom scale
initialZoomTransformMatrixidentityInitial zoom transform
classNamestring""Additional CSS class

ChoroplethFeatureComponent

Renders the geographic feature paths with hover states and optional patterns.

PropTypeDefaultDescription
fillstring-Fill color for all features (overrides getFeatureColor)
strokestring"var(--chart-grid)"Stroke color for borders
strokeWidthnumber0.5Border stroke width
fadedOpacitynumber0.4Opacity when another feature is hovered
getFeatureColor(feature, index) => string-Custom color function
patternsReactNode-Pattern definitions using @visx/pattern components
getFeaturePattern(feature, index) => string | null-Return pattern ID for a feature

ChoroplethGraticule

Renders optional graticule (latitude/longitude grid lines).

PropTypeDefaultDescription
strokestring"rgba(255,255,255,0.1)"Line color
strokeWidthnumber0.5Line width
step[number, number][10, 10]Grid step intervals [longitude, latitude] in degrees

ChoroplethTooltip

Displays tooltips for features on hover, following the mouse position.

PropTypeDefaultDescription
content(props) => ReactNode-Custom tooltip renderer
formatValue(value) => stringtoLocaleStringValue formatter
getFeatureName(feature, index) => string-Custom name getter
getFeatureValue(feature, index) => number-Value getter for display
valueLabelstring"Value"Label for the value row
classNamestring""Additional CSS class

Data Format

The choropleth expects a GeoJSON FeatureCollection:

interface FeatureCollection {
  type: "FeatureCollection";
  features: Array<{
    type: "Feature";
    geometry: Geometry; // Polygon, MultiPolygon, etc.
    properties: {
      name?: string;
      id?: string | number;
      [key: string]: unknown;
    };
  }>;
}

For TopoJSON data, convert it using topojson-client:

import * as topojson from "topojson-client";

const geojson = topojson.feature(topology, topology.objects.countries);

Examples

Web Analytics

Use getFeatureColor to create a color scale based on data values. This example shows visitor traffic by country, with brighter colors indicating higher traffic:

Loading map data...
const visitorsByCountry = { "United States": 125000, ... };function getVisitorColor(feature) {const visitors = visitorsByCountry[feature.properties?.name];if (!visitors) return "var(--chart-5)";// Map to chart colors based on normalized valueif (normalized > 0.7) return "var(--chart-1)";if (normalized > 0.4) return "var(--chart-2)";...}<ChoroplethChart data={geojson} aspectRatio="16 / 9"><ChoroplethFeatureComponent getFeatureColor={getVisitorColor} /><ChoroplethTooltip getFeatureValue={getVisitorValue} valueLabel="Visitors" /></ChoroplethChart>

Zoom Controls

Enable zoom with zoomEnabled and use useChoroplethZoom() hook to create custom controls:

Loading map data...
import { useChoroplethZoom } from "@bklitui/ui/charts";import { ZoomIn, ZoomOut, RotateCcw } from "lucide-react";function ZoomControls() {const { zoom } = useChoroplethZoom();if (!zoom) return null;return (  <div className="absolute right-3 top-3 flex flex-col gap-1">    <Button onClick={() => zoom.scale({ scaleX: 1.2, scaleY: 1.2 })}>      <ZoomIn />    </Button>    <Button onClick={() => zoom.scale({ scaleX: 0.8, scaleY: 0.8 })}>      <ZoomOut />    </Button>    <Button onClick={() => zoom.reset()}>      <RotateCcw />    </Button>  </div>);}<ChoroplethChart data={geojson} aspectRatio="16 / 9" zoomEnabled><ChoroplethFeatureComponent fill="var(--chart-1)" /><ChoroplethTooltip /><ZoomControls /></ChoroplethChart>

Diagonal Lines Pattern

Use PatternLines from @visx/pattern to create diagonal line patterns:

Loading map data...
<ChoroplethChart data={geojson} aspectRatio="16 / 9"><ChoroplethGraticule /><ChoroplethFeatureComponent  patterns={    <>      <PatternLines id="pattern-1" stroke="var(--chart-1)" ... />      <PatternLines id="pattern-2" stroke="var(--chart-2)" ... />    </>  }  getFeaturePattern={(feature) => getPatternId(feature)}/><ChoroplethTooltip /></ChoroplethChart>

Dependencies

This component requires:

pnpm add @visx/geo @visx/responsive @visx/pattern @visx/zoom topojson-client motion react-use-measure