Customization
Custom Styling
This is an optional more advanced customization option. When used, the developer has full control to define the color, opacity and any other style element of a country with data record.
This is done by passing your custom implementation of the styleFunction. The function receives as input the country context that includes country, countryValue, color, minValue and maxValue, and returns a React CSSProperties object. Note that countryValue can be a number, string, or undefined, for which case you may need to handle the styling differently.
For example:
import { CountryContext } from "react-svg-worldmap";
const stylingFunction = ({
countryValue,
minValue,
maxValue,
country,
color,
}: CountryContext) => {
const calculatedValue =
typeof countryValue === "string" ? minValue : countryValue;
const opacityLevel =
calculatedValue !== undefined
? 0.1 + (1.5 * (calculatedValue - minValue)) / (maxValue - minValue)
: 0;
return {
fill: country === "US" ? "blue" : color,
fillOpacity: opacityLevel,
stroke: "green",
strokeWidth: 1,
strokeOpacity: 0.2,
cursor: "pointer",
};
};
Styling and testing hooks
The map's SVG carries stable attributes you can target from CSS or tests, so you don't depend on element order:
- Each country
<path>hasdata-country-code(ISO code, e.g.US) anddata-country-name(e.g.United States). - The map is drawn in layers. Each layer is a
<g>directly under the<svg>withdata-map-layeranddata-map-layer-order(paint order, back to front):ocean,countries,disputed-territories(only withshowDisputedTerritories),labels(fromtextLabelFunction),country-labels(only withzoom), andpins(only withpins). The list is exported asmapRenderingLayers. Layers that move with the map share thecountrieslayer'stransform. - Each pin is a
<g data-map-pin>(itskind, defaultpin) withdata-country-codewhen the pin has acountryCode. Each country label is a<text data-country-code>in thecountry-labelslayer. - With
zoom, the<svg>hasdata-zoom-scale(the current zoom level) and sits in a<div class="worldmap__zoom-viewport">together with the zoom buttons. - The
oceanlayer holds one<rect data-map-ocean>filled withbackgroundColor. It has the same colour as the figure behind it, so the map looks the same as before. - With
frame, the frame is a<rect data-map-frame>drawn between the ocean and the countries.
.my-map [data-map-ocean] {
fill: #a0d7eb;
}
.my-map [data-country-code="FR"] {
stroke-width: 2;
}
screen.getByRole("img").querySelector('[data-country-code="US"]');
Sizing
The size can be a number specifying the width of the map, in pixels. It can also be one of the following aliases:
| Alias | Width |
|---|---|
sm | 240 |
md | 336 |
lg | 480 |
xl | 640 |
xxl | 1200 |
When the size is set to responsive, the map fills the width of its container and grows and shrinks continuously as the container resizes. The height is always width * 3/4.
Because the map is not capped by the viewport height, a wide container can produce a map taller than the screen. To limit it, constrain the container, for example with max-width, or pass a number as the size.
The container needs a width that doesn't depend on its content, such as a block element or a flex item with width: 100% or flex: 1. In a shrink-to-fit container (a flex item with no width or flex-grow, inline-block, a float, or an auto grid column), the map and its container size each other, so the map can shrink but will not grow back.
The algorithm used in responsive sizing is:
const width = availableWidth; // measured container width
Rich interactions
richInteraction captures a few events inside the SVG:
- Double-clicking zooms in twice, then restores the original scale.
- With the map focused,
+zooms in to the centre (up to 4x) and-resets.
Zoom, pins and labels
For full zoom and pan, pass zoom instead: buttons, drag, double-click, keyboard, and ctrl / ⌘ + wheel or trackpad pinch, with maxScale and other options. It also shows country names that fit inside their countries. pins draws captioned markers at longitude / latitude, with or without zoom.
<WorldMap
data={data}
zoom={{ maxScale: 6 }}
pins={[{ caption: "Paris", coordinates: [2.35, 48.86], countryCode: "FR" }]}
/>
Their colors are props, so they can follow your theme (for example a dark mode):
| Prop | Default | Used for |
|---|---|---|
pinColor | #b91c1c | Fill of the pin markers. |
pinTextColor | #1f2937 | Pin captions. |
pinOutlineColor | #fff | Outline of the markers and halo behind the captions. |
labelColor | #222 | Country labels. |
labelHaloColor | none | Optional halo behind the country labels. |
The zoom buttons can be styled through [aria-label="Map zoom controls"] button, or hidden with zoom={{ showControls: false }}.
Projections
WorldMap uses Mercator by default. Pass projection="equalEarth" for the Equal Earth equal-area projection, where countries keep their true relative size.
<WorldMap data={data} projection="equalEarth" />
- Default stays
mercator, so existing maps are unchanged. - Equal Earth uses a 2:1 SVG frame (height = width / 2) and draws a globe outline in
borderColor. - Tooltips, callbacks,
richInteraction,zoom,pins, andshowDisputedTerritorieswork in both projections. textLabelFunctionpositions are SVG pixels; labels placed for Mercator may need new coordinates in Equal Earth.
See the Equal Earth example.