Create beautiful, interactive SVG maps in React Native with d3-geo and TopoJSON using a declarative API. A React Native port of react-simple-maps.
- 🗺️ 15+ map projections — Mercator, Orthographic, Equal Earth, Natural Earth, and more
- 📍 Markers — Place markers at any coordinates with custom SVG children
- ✏️ Annotations — Label locations with connector lines
- 🛫 Lines — Draw routes/connections between coordinates
- 🌐 Graticule — Latitude/longitude grid overlay
- 🔵 Sphere — Globe boundary with clipping
- 👆 Interactive — Press handlers on geographies and markers
- 🔍 Zoom & Pan — Pinch-to-zoom and drag gestures (optional, separate import)
- 📦 TypeScript — Full type definitions included
- ⚡ Tree-shakeable — ESM output, zoom module is a separate entry point
npm install react-native-simple-map react-native-svg| Package | Required | Purpose |
|---|---|---|
react-native-svg |
Yes | SVG rendering |
react-native-gesture-handler |
Only for ZoomableGroup | Gesture handling |
react-native-reanimated |
Only for ZoomableGroup | Smooth animations |
If you want zoom/pan support:
npm install react-native-gesture-handler react-native-reanimatedNote: After installing native dependencies, rebuild your app (
npx react-native run-androidorrun-ios).
import { ComposableMap, Geographies, Geography } from 'react-native-simple-map';
const geoUrl = 'https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json';
export default function WorldMap() {
return (
<ComposableMap>
<Geographies geography={geoUrl}>
{({ geographies }) =>
geographies.map((geo) => (
<Geography
key={geo.rsmKey}
geography={geo}
fill="#D6D6DA"
stroke="#FFFFFF"
strokeWidth={0.5}
/>
))
}
</Geographies>
</ComposableMap>
);
}Root container that sets up the SVG canvas and map projection.
<ComposableMap
width={800} // SVG viewport width (default: 800)
height={600} // SVG viewport height (default: 600)
projection="geoMercator" // Projection name or factory function
projectionConfig={{
scale: 140,
center: [0, 0],
rotate: [0, 0, 0],
}}
>
{children}
</ComposableMap>Available projections: geoEqualEarth, geoMercator, geoOrthographic, geoNaturalEarth1, geoAlbers, geoAlbersUsa, geoAzimuthalEqualArea, geoAzimuthalEquidistant, geoConicConformal, geoConicEqualArea, geoConicEquidistant, geoEquirectangular, geoGnomonic, geoStereographic, geoTransverseMercator
Loads and parses TopoJSON data, providing geography features to children.
<Geographies geography={geoUrl}>
{({ geographies, outline, borders, path, projection }) =>
geographies.map((geo) => (
<Geography key={geo.rsmKey} geography={geo} />
))
}
</Geographies>| Prop | Type | Description |
|---|---|---|
geography |
string | object |
TopoJSON URL or inline object |
children |
function |
Render function receiving { geographies, outline, borders, path, projection } |
parseGeographies |
function |
Optional transform applied to features array |
Renders a single geographic feature as an SVG path.
<Geography
geography={geo}
fill="#EAEAEC"
stroke="#D6D6DA"
strokeWidth={0.5}
onPress={(geo) => console.log(geo.properties.name)}
style={{
default: { fill: '#D6D6DA' },
pressed: { fill: '#E42' },
}}
/>| Prop | Type | Description |
|---|---|---|
geography |
GeographyFeature |
Feature object from Geographies render prop |
fill |
string |
Fill color |
stroke |
string |
Border color |
strokeWidth |
number |
Border width |
onPress |
(geo) => void |
Press handler |
onPressIn |
(geo) => void |
Touch start handler |
onPressOut |
(geo) => void |
Touch end handler |
style |
{ default?, pressed? } |
Style states |
Places children at projected geographic coordinates.
import { Circle } from 'react-native-svg';
<Marker coordinates={[-74.006, 40.7128]}>
<Circle r={4} fill="#F53" />
</Marker>| Prop | Type | Description |
|---|---|---|
coordinates |
[number, number] |
[longitude, latitude] |
children |
ReactNode |
SVG elements to render at the location |
onPress |
() => void |
Press handler |
Draws a geodesic line between two or more coordinates.
<Line
from={[-74.006, 40.7128]}
to={[2.3522, 48.8566]}
stroke="#F53"
strokeWidth={2}
/>| Prop | Type | Default | Description |
|---|---|---|---|
from |
[number, number] |
[0, 0] |
Start coordinates |
to |
[number, number] |
[0, 0] |
End coordinates |
coordinates |
[number, number][] |
— | Multi-point path (overrides from/to) |
stroke |
string |
"currentColor" |
Line color |
strokeWidth |
number |
3 |
Line width |
fill |
string |
"transparent" |
Fill (usually transparent for lines) |
Renders a label with a connector line from a geographic coordinate.
import { Text as SvgText } from 'react-native-svg';
<Annotation subject={[2.3522, 48.8566]} dx={-40} dy={-30}>
<SvgText fontSize={12} fill="#333">Paris</SvgText>
</Annotation>| Prop | Type | Default | Description |
|---|---|---|---|
subject |
[number, number] |
— | Target coordinates |
dx |
number |
30 |
Horizontal offset for label |
dy |
number |
30 |
Vertical offset for label |
curve |
number |
0 |
Connector line curvature |
connectorProps |
object |
{} |
SVG props for the connector path |
Renders a latitude/longitude grid.
<Graticule stroke="#ccc" strokeWidth={0.3} step={[20, 20]} />| Prop | Type | Default | Description |
|---|---|---|---|
fill |
string |
"transparent" |
Grid fill |
stroke |
string |
"#ccc" |
Grid line color |
strokeWidth |
number |
0.5 |
Grid line width |
step |
[number, number] |
[10, 10] |
Grid spacing in degrees |
Renders the globe boundary with an optional clip path.
<Sphere fill="#E8F4FD" stroke="#999" strokeWidth={0.5} />| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
"rsm-sphere" |
ClipPath ID |
fill |
string |
"transparent" |
Background fill |
stroke |
string |
"#000" |
Border color |
strokeWidth |
number |
0.5 |
Border width |
Adds pinch-to-zoom and drag-to-pan gestures. Requires react-native-gesture-handler and react-native-reanimated.
import { ZoomableGroup } from 'react-native-simple-map/zoom';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
<GestureHandlerRootView style={{ flex: 1 }}>
<ComposableMap>
<ZoomableGroup
center={[0, 0]}
zoom={1}
minZoom={1}
maxZoom={8}
onMove={({ x, y, zoom }) => console.log(zoom)}
>
<Geographies geography={geoUrl}>
{({ geographies }) =>
geographies.map((geo) => (
<Geography key={geo.rsmKey} geography={geo} />
))
}
</Geographies>
</ZoomableGroup>
</ComposableMap>
</GestureHandlerRootView>| Prop | Type | Default | Description |
|---|---|---|---|
center |
[number, number] |
[0, 0] |
Initial center coordinates |
zoom |
number |
1 |
Initial zoom level |
minZoom |
number |
1 |
Minimum zoom |
maxZoom |
number |
8 |
Maximum zoom |
translateExtent |
[[x0, y0], [x1, y1]] |
— | Pan bounds |
onMoveStart |
function |
— | Gesture start callback |
onMove |
function |
— | Gesture move callback { x, y, zoom } |
onMoveEnd |
function |
— | Gesture end callback |
Important: Wrap your app (or screen) in
<GestureHandlerRootView>when using ZoomableGroup.
Access the map projection and path generator from any child component.
import { useMapContext } from 'react-native-simple-map';
const { projection, path, width, height } = useMapContext();Fetch and parse TopoJSON data programmatically.
import { useGeographies } from 'react-native-simple-map';
const { geographies, outline, borders } = useGeographies({ geography: geoUrl });This library works with TopoJSON format. Recommended sources:
- World Atlas —
https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json - US Atlas —
https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json - Custom — Any valid TopoJSON file or URL
This library aims for API parity with react-simple-maps. Key differences for React Native:
| Web | React Native |
|---|---|
className prop |
Use inline SVG props (fill, stroke, etc.) |
onMouseEnter/onMouseLeave |
onPress/onPressIn/onPressOut |
style.hover state |
Not available (no hover on mobile) |
| d3-zoom (mouse wheel) | Pinch + pan gestures via react-native-gesture-handler |
| Single import | ZoomableGroup is a separate import (/zoom) |
All components are fully typed. Import types directly:
import type {
ComposableMapProps,
GeographiesProps,
GeographyProps,
GeographyFeature,
MarkerProps,
AnnotationProps,
LineProps,
SphereProps,
GraticuleProps,
ZoomableGroupProps,
ProjectionConfig,
MapContextValue,
ZoomPanContextValue,
} from 'react-native-simple-map';See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT