Something new is coming.Join the waitlist

World Map

Previous

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

PropTypeDescription
selectedCountriesSet<string>Country names (matching geo.properties.name) that should render in the selected color.
onCountryClick(geo) => voidFired when a country path is clicked. The argument carries properties.name and rsmKey. Ignored when static is true.
staticbooleanWhen 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.
userCountsRecord<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.
classNamestringForwarded 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.