World Map
An interactive, zoomable world map with country selection and a hover tooltip.
Installation
npx shadcn@latest add https://ui.srb.codes/r/world-map.json
Usage
"use client";
import * as React from "react";
import WorldMap from "@/components/world-map";
export function MapPicker() {
const [selected, setSelected] = React.useState<Set<string>>(new Set());
return (
<div className="aspect-[16/9] w-full overflow-hidden rounded-lg border">
<WorldMap
selectedCountries={selected}
onCountryClick={(geo) => {
const name = geo.properties.name;
setSelected((prev) => {
const next = new Set(prev);
next.has(name) ? next.delete(name) : next.add(name);
return next;
});
}}
/>
</div>
);
}Geography data
The component imports its TopoJSON from a co-located world-map.geo.json. The file ships as an empty topology so the import resolves out of the box; replace its contents with a real world atlas to render countries. The standard choice is the world-atlas countries-110m.json — fetch it once and commit it next to the component. Whenever you swap the JSON, the map updates without any code changes.
Props
| Prop | Type | Description |
|---|---|---|
selectedCountries | Set<string> | Country names (matching geo.properties.name) that should render in the selected color. |
onCountryClick | (geo) => void | Fired when a country path is clicked. The argument carries properties.name and rsmKey. Ignored when static is true. |
static | boolean | When true, render a non-interactive map: zoom and pan are disabled, the hover tooltip is suppressed, hover styles collapse to default, and clicks are ignored. Useful for read-only dashboards. Defaults to false. |
userCounts | Record<string, number> | Optional user counts per country, keyed by country name. When set, hovering a country with an entry shows the formatted count beneath the country name in the tooltip. |
className | string | Forwarded to the outer wrapper. The component fills its container by default. |
Theming
Country fills are driven by CSS variables (--primary, --muted, --accent, --background, --popover), so the map automatically picks up the active theme. To recolor locally, override those variables on a parent element.