
Product
Introducing Repository Access Permissions and Custom Roles
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.
@vnedyalk0v/react19-simple-maps
Advanced tools
An svg map chart component built exclusively for React 19+ - Modern TypeScript-first library with cutting-edge React patterns
Create beautiful, interactive SVG maps in React with d3-geo and topojson using a declarative, TypeScript-first API built exclusively for React 19+.
π΄ This is a modernized fork of the original react-simple-maps by Richard Zimerman, completely rewritten with full TypeScript support, React 19 compatibility, and modern development practices by Georgi Nedyalkov.
@vnedyalk0v/react19-simple-maps makes working with SVG maps in React effortless. It handles complex tasks like panning, zooming, projections, and rendering optimization while leveraging the power of d3-geo and topojson-client without requiring the entire d3 library.
Since the library leaves DOM work to React, it integrates seamlessly with other React libraries like react-spring for animations and react-annotation for enhanced annotations.
Why Choose This Package:
use API and enhanced error boundaries# npm
npm install @vnedyalk0v/react19-simple-maps
# yarn
yarn add @vnedyalk0v/react19-simple-maps
# pnpm
pnpm add @vnedyalk0v/react19-simple-maps
ESM-only: This package only supports
importsyntax.require(...)is not supported.
# Configure npm to use GitHub Packages for @vnedyalk0v scope
echo "@vnedyalk0v:registry=https://npm.pkg.github.com" >> ~/.npmrc
# Install from GitHub Packages
npm install @vnedyalk0v/react19-simple-maps
You can import utility helpers directly from the ./utils subpath:
import {
validateGeographyUrl,
configureSRI,
} from '@vnedyalk0v/react19-simple-maps/utils';
Migrating from the original react-simple-maps? We've got you covered!
Quick Migration:
npm uninstall react-simple-maps && npm install @vnedyalk0v/react19-simple-mapsfrom "react-simple-maps" β from "@vnedyalk0v/react19-simple-maps"[lon, lat] β createCoordinates(lon, lat)π Complete Migration Guide - Detailed step-by-step instructions, breaking changes, and troubleshooting tips.
The package automatically includes these dependencies:
d3-geo ^3.1.0 - Geographic projections and utilitiesd3-zoom ^3.0.0 - Zoom and pan behaviord3-selection ^3.0.0 - DOM selection utilitiesd3-color ^3.1.0 - Color manipulationd3-interpolate ^3.0.1 - Value interpolationtopojson-client ^3.1.0 - TopoJSON parsing and processingreact19-simple-maps provides a set of composable React components for creating interactive SVG maps. You can combine these components to build everything from simple world maps to complex interactive visualizations.
import React from 'react';
import {
ComposableMap,
Geographies,
Geography,
} from '@vnedyalk0v/react19-simple-maps';
// URL to a valid TopoJSON file
const geoUrl = 'https://unpkg.com/world-atlas@2/countries-110m.json';
const MapChart = () => {
return (
<ComposableMap
projection="geoEqualEarth"
projectionConfig={{
scale: 147,
center: [0, 0],
}}
width={800}
height={500}
>
<Geographies geography={geoUrl}>
{({ geographies }) =>
geographies.map((geo) => (
<Geography
key={geo.rsmKey}
geography={geo}
style={{
default: { fill: '#D6D6DA', outline: 'none' },
hover: { fill: '#F53', outline: 'none' },
pressed: { fill: '#E42', outline: 'none' },
}}
/>
))
}
</Geographies>
</ComposableMap>
);
};
export default MapChart;
import React, { useState } from 'react';
import {
ComposableMap,
Geographies,
Geography,
Marker,
ZoomableGroup,
createCoordinates,
createScaleExtent,
createTranslateExtent,
} from '@vnedyalk0v/react19-simple-maps';
import type { Feature, Geometry } from 'geojson';
const geoUrl = 'https://unpkg.com/world-atlas@2/countries-50m.json';
const InteractiveMap: React.FC = () => {
const [selectedCountry, setSelectedCountry] = useState<string | null>(null);
const handleGeographyClick = (geography: Feature<Geometry>) => {
const countryName = geography.properties?.name || 'Unknown';
setSelectedCountry(countryName);
};
return (
<div>
{selectedCountry && <p>Selected: {selectedCountry}</p>}
<ComposableMap projection="geoEqualEarth" width={800} height={500}>
<ZoomableGroup
zoom={1}
center={createCoordinates(0, 0)}
minZoom={0.5}
maxZoom={8}
scaleExtent={createScaleExtent(0.5, 8)}
translateExtent={createTranslateExtent(
createCoordinates(-2000, -1000),
createCoordinates(2000, 1000),
)}
>
<Geographies geography={geoUrl}>
{({ geographies }) =>
geographies.map((geo) => (
<Geography
key={geo.rsmKey}
geography={geo}
onClick={() => handleGeographyClick(geo)}
style={{
default: {
fill:
selectedCountry === geo.properties?.name
? '#1976d2'
: '#D6D6DA',
outline: 'none',
stroke: '#FFFFFF',
strokeWidth: 0.5,
},
hover: { fill: '#F53', cursor: 'pointer' },
pressed: { fill: '#E42' },
}}
/>
))
}
</Geographies>
{/* Add a marker for New York */}
<Marker coordinates={createCoordinates(-74.006, 40.7128)}>
<circle r={5} fill="#F53" stroke="#fff" strokeWidth={2} />
<text
textAnchor="middle"
y={-10}
style={{ fontSize: '12px', fill: '#333' }}
>
New York
</text>
</Marker>
</ZoomableGroup>
</ComposableMap>
</div>
);
};
export default InteractiveMap;
Check out our comprehensive examples in the examples/ directory:
The examples use the Equal Earth projection, which provides an accurate representation of land areas. Learn more about this projection on Shaded Relief and Wikipedia.
The main wrapper component that provides the SVG context and projection system.
Props:
projection - Map projection (string name or d3-geo projection function)projectionConfig - Configuration for built-in projectionswidth, height - SVG dimensionsclassName - CSS class namedebug - Enable debug logging (default: false, opt-in only)metadata - Optional metadata for SEO and accessibilityimport {
ComposableMap,
createCoordinates,
} from '@vnedyalk0v/react19-simple-maps';
<ComposableMap
projection="geoEqualEarth"
projectionConfig={{
scale: 147,
center: createCoordinates(0, 0),
rotate: [0, 0, 0],
}}
width={800}
height={600}
className="my-map"
>
{/* Map content */}
</ComposableMap>;
Renders geographic features from TopoJSON or GeoJSON data with built-in error handling.
Props:
geography - URL string, TopoJSON object, or GeoJSON FeatureCollectionparseGeographies - Optional function to transform geography dataclassName - CSS class nameimport { Geographies, Geography } from '@vnedyalk0v/react19-simple-maps';
<Geographies geography="https://unpkg.com/world-atlas@2/countries-110m.json">
{({ geographies, outline, borders }) =>
geographies.map((geo) => (
<Geography
key={geo.rsmKey}
geography={geo}
onClick={(event) => console.log('Clicked:', geo.properties?.name)}
onMouseEnter={(event) => console.log('Hover:', geo.properties?.name)}
/>
))
}
</Geographies>;
Individual geographic feature component with enhanced interaction support.
Enhanced Event Handlers:
All event handlers now receive geographic data as a second parameter:
<Geography
geography={geo}
onClick={(event, data) => {
console.log('Country:', data.geography.properties?.name);
console.log('Centroid:', data.centroid);
console.log('Bounds:', data.bounds);
console.log('Coordinates:', data.coordinates);
}}
onMouseEnter={(event, data) => {
// Access to rich geographic data
}}
/>
Props:
geography - GeoJSON feature objectstyle - Conditional styling object with default, hover, pressed statesonClick, onMouseEnter, onMouseLeave, onFocus, onBlur
(event, GeographyEventData) parametersProvides zoom and pan functionality with configurable constraints. Supports both simple and advanced APIs.
Simple API (Recommended):
import { ZoomableGroup, createZoomConfig, createPanConfig } from '@vnedyalk0v/react19-simple-maps';
// Easy zoom configuration
<ZoomableGroup
zoom={1}
center={createCoordinates(0, 0)}
{...createZoomConfig(0.5, 8)} // minZoom, maxZoom
>
{/* Content */}
</ZoomableGroup>
// Or use direct props
<ZoomableGroup
zoom={1}
center={createCoordinates(0, 0)}
minZoom={0.5}
maxZoom={8}
enableZoom={true}
>
{/* Content */}
</ZoomableGroup>
Props:
zoom - Current zoom levelcenter - Center coordinatesminZoom, maxZoom - Zoom level constraints (simple API)enableZoom, enablePan - Enable/disable behaviors (simple API)scaleExtent - Alternative to minZoom/maxZoom using branded typestranslateExtent - Pan boundariesfilterZoomEvent - Custom zoom event filteringonMoveStart, onMove, onMoveEnd - Movement event handlersimport {
ZoomableGroup,
createCoordinates,
createScaleExtent,
createTranslateExtent,
} from '@vnedyalk0v/react19-simple-maps';
// Approach 1: Using enableZoom/enablePan with explicit constraints
<ZoomableGroup
zoom={1}
center={createCoordinates(0, 0)}
enableZoom={true}
minZoom={0.5}
maxZoom={8}
scaleExtent={createScaleExtent(0.5, 8)}
enablePan={true}
translateExtent={createTranslateExtent(
createCoordinates(-1000, -500),
createCoordinates(1000, 500),
)}
onMoveEnd={(position) => console.log('New position:', position)}
>
{/* Zoomable content */}
</ZoomableGroup>
// Approach 2: Simplified with just constraints
<ZoomableGroup
zoom={1}
center={createCoordinates(0, 0)}
minZoom={0.5}
maxZoom={8}
translateExtent={createTranslateExtent(
createCoordinates(-1000, -500),
createCoordinates(1000, 500),
)}
>
{/* Zoomable content */}
</ZoomableGroup>;
Add custom markers to specific coordinates on your map.
Props:
coordinates - Geographic coordinates using branded typesclassName - CSS class nameonClick, onMouseEnter, onMouseLeave, onFocus, onBlurimport { Marker, createCoordinates } from '@vnedyalk0v/react19-simple-maps';
<Marker coordinates={createCoordinates(-74.006, 40.7128)}>
<circle r={5} fill="#F53" stroke="#fff" strokeWidth={2} />
<text textAnchor="middle" y={-10} style={{ fontSize: '12px' }}>
New York
</text>
</Marker>;
Create annotations with connector lines pointing to specific locations.
Props:
subject - Target coordinatesdx, dy - Offset from subjectcurve - Connector curve amountconnectorProps - SVG props for the connector lineimport { Annotation, createCoordinates } from '@vnedyalk0v/react19-simple-maps';
<Annotation
subject={createCoordinates(-74.006, 40.7128)}
dx={-90}
dy={-30}
connectorProps={{
stroke: '#FF5533',
strokeWidth: 2,
strokeLinecap: 'round',
}}
>
<text textAnchor="end" alignmentBaseline="middle" fill="#F53">
New York City
</text>
</Annotation>;
Line - Draw lines between coordinatesGraticule - Add coordinate grid linesSphere - Add map outline/backgroundGeographyErrorBoundary - React 19 error boundary for geography loadingThe package includes comprehensive TypeScript definitions with strict typing and branded types for enhanced type safety.
import {
createCoordinates,
createLongitude,
createLatitude,
createScaleExtent,
createTranslateExtent,
} from '@vnedyalk0v/react19-simple-maps';
// Branded types prevent coordinate mistakes
const longitude = createLongitude(-74.006); // Type: Longitude
const latitude = createLatitude(40.7128); // Type: Latitude
const coordinates = createCoordinates(-74.006, 40.7128); // Type: Coordinates
// Scale and translate extents
const scaleExtent = createScaleExtent(0.5, 8);
const translateExtent = createTranslateExtent(
createCoordinates(-1000, -500),
createCoordinates(1000, 500),
);
Extract geographic data from features for enhanced interactions:
import {
getGeographyCentroid,
getGeographyBounds,
getBestGeographyCoordinates,
isValidCoordinates,
} from '@vnedyalk0v/react19-simple-maps';
// Extract centroid for map centering
const centroid = getGeographyCentroid(geography);
if (centroid) {
setMapCenter(centroid);
}
// Get bounding box for zoom-to-fit
const bounds = getGeographyBounds(geography);
if (bounds) {
const [southwest, northeast] = bounds;
// Use bounds for map fitting
}
// Get best available coordinates
const coords = getBestGeographyCoordinates(geography);
import type {
ComposableMapProps,
GeographyProps,
GeographyEventData,
MarkerProps,
ProjectionConfig,
Position,
SimpleZoomableGroupProps,
} from '@vnedyalk0v/react19-simple-maps';
import type { Feature, Geometry } from 'geojson';
// Typed projection configuration
const projectionConfig: ProjectionConfig = {
scale: 147,
center: createCoordinates(0, 0),
rotate: [0, 0, 0],
};
// Enhanced event handlers with geographic data
const handleGeographyClick = (
event: React.MouseEvent,
data: GeographyEventData,
) => {
console.log('Country:', data.geography.properties?.name);
console.log('Centroid:', data.centroid);
if (data.centroid) {
setMapCenter(data.centroid);
}
};
const handleZoomEnd = (position: Position) => {
console.log('New position:', position.coordinates, 'Zoom:', position.zoom);
};
The library works with any valid TopoJSON or GeoJSON data, giving you complete flexibility in map visualization.
// World maps
const worldCountries = 'https://unpkg.com/world-atlas@2/countries-110m.json';
const worldCountriesDetailed = 'https://unpkg.com/world-atlas@2/countries-50m.json';
// US maps
const usStates = 'https://unpkg.com/us-atlas@3/states-10m.json';
const usCounties = 'https://unpkg.com/us-atlas@3/counties-10m.json';
// Usage
<Geographies geography={worldCountries}>
{({ geographies }) => /* render countries */}
</Geographies>
To create your own TopoJSON maps from shapefiles:
Tutorial: "How to convert and prepare TopoJSON files for interactive mapping with d3"
The library supports all major d3-geo projections out of the box:
// Popular projections
<ComposableMap projection="geoEqualEarth" /> // Equal area, good for world maps
<ComposableMap projection="geoMercator" /> // Web maps standard
<ComposableMap projection="geoNaturalEarth1" /> // Compromise projection
<ComposableMap projection="geoAlbersUsa" /> // US-specific projection
<ComposableMap projection="geoOrthographic" /> // Globe view
Use any d3-geo projection or create your own:
import { geoMercator, geoConicEqualArea } from 'd3-geo';
// Custom Mercator
const customMercator = geoMercator()
.scale(100)
.translate([400, 300])
.rotate([-11, 0]);
// Custom conic projection for specific regions
const customConic = geoConicEqualArea()
.parallels([29.5, 45.5])
.scale(1000)
.translate([480, 250])
.rotate([96, 0]);
<ComposableMap projection={customMercator}>{/* Map content */}</ComposableMap>;
import {
ZoomableGroup,
createCoordinates,
createTranslateExtent,
} from '@vnedyalk0v/react19-simple-maps';
<ZoomableGroup
zoom={2}
center={createCoordinates(-100, 40)}
minZoom={0.5}
maxZoom={10}
translateExtent={createTranslateExtent(
createCoordinates(-2000, -1000),
createCoordinates(2000, 1000),
)}
filterZoomEvent={(event) => !event.ctrlKey} // Disable zoom with Ctrl
onMoveStart={(position, event) => console.log('Move started')}
onMove={(position, event) => console.log('Moving:', position)}
onMoveEnd={(position, event) => console.log('Move ended:', position)}
>
{/* Zoomable content */}
</ZoomableGroup>;
The library includes comprehensive security features designed for production applications.
import {
configureGeographySecurity,
enableDevelopmentMode,
DEFAULT_GEOGRAPHY_FETCH_CONFIG,
} from '@vnedyalk0v/react19-simple-maps/utils';
// Default: Strict HTTPS-only mode (recommended for production)
// No configuration needed - secure by default
// For development with local geography files:
if (process.env.NODE_ENV === 'development') {
enableDevelopmentMode(true); // Allows HTTP localhost
}
// Custom security configuration:
configureGeographySecurity({
STRICT_HTTPS_ONLY: true, // Force HTTPS only
ALLOW_HTTP_LOCALHOST: false, // Disable HTTP localhost
TIMEOUT_MS: 5000, // 5 second timeout
MAX_RESPONSE_SIZE: 10 * 1024 * 1024, // 10MB max
ALLOWED_CONTENT_TYPES: [
// Restrict content types
'application/json',
'application/geo+json',
],
});
Protect against tampered external resources with built-in SRI validation:
import {
configureSRI,
enableStrictSRI,
addCustomSRI,
generateSRIHash,
generateSRIForUrls,
} from '@vnedyalk0v/react19-simple-maps/utils';
// Enable strict SRI for all external resources
enableStrictSRI();
// Add custom SRI for your geography data
addCustomSRI('https://your-domain.com/data.json', {
algorithm: 'sha384',
hash: 'sha384-your-calculated-hash',
enforceIntegrity: true,
});
// Generate SRI hash for a URL (development utility)
const hash = await generateSRIHash('https://example.com/data.json');
console.log('SRI Hash:', hash);
// Batch generate SRI for multiple URLs
const sriMap = await generateSRIForUrls([
'https://unpkg.com/world-atlas@2/countries-110m.json',
'https://unpkg.com/us-atlas@3/states-10m.json',
]);
Built-in error boundaries for robust geography loading:
import { GeographyErrorBoundary } from '@vnedyalk0v/react19-simple-maps';
<GeographyErrorBoundary
fallback={(error, retry) => (
<div>
<p>Failed to load map: {error.message}</p>
<button onClick={retry}>Retry</button>
</div>
)}
onError={(error) => console.error('Geography error:', error)}
>
<Geographies geography="https://example.com/map.json">
{({ geographies }) => /* render geographies */}
</Geographies>
</GeographyErrorBoundary>
const geographyStyle = {
default: {
fill: '#D6D6DA',
outline: 'none',
stroke: '#FFFFFF',
strokeWidth: 0.5,
},
hover: {
fill: '#F53',
outline: 'none',
cursor: 'pointer',
},
pressed: {
fill: '#E42',
outline: 'none',
},
};
<Geography geography={geo} style={geographyStyle} />;
const getCountryStyle = (
countryName: string,
selectedCountry: string | null,
) => ({
default: {
fill: selectedCountry === countryName ? '#1976d2' : '#D6D6DA',
outline: 'none',
stroke: '#FFFFFF',
strokeWidth: 0.5,
},
hover: {
fill: selectedCountry === countryName ? '#1565c0' : '#F53',
cursor: 'pointer',
},
});
<Geography
geography={geo}
style={getCountryStyle(geo.properties?.name, selectedCountry)}
/>;
// Use CSS classes for styling
<ComposableMap className="world-map">
<Geographies geography={geoUrl} className="countries">
{({ geographies }) =>
geographies.map((geo) => (
<Geography
key={geo.rsmKey}
geography={geo}
className={`country country-${geo.properties?.iso_a2?.toLowerCase()}`}
/>
))
}
</Geographies>
</ComposableMap>
This is a complete rewrite focused exclusively on React 19+. No backward compatibility with React 18 or earlier versions.
any typesuse API, enhanced error boundaries, improved Suspensenpm install @vnedyalk0v/react19-simple-mapscreateCoordinates()The library provides opt-in debugging capabilities to help with development and troubleshooting.
By default, the library is quiet and produces no console output. You can enable debugging in two ways:
1. Environment Variable (Global)
# Enable debug mode for all maps
REACT_SIMPLE_MAPS_DEBUG=true npm start
# Or in your .env file
REACT_SIMPLE_MAPS_DEBUG=true
2. Component Prop (Per Map)
<ComposableMap debug={true}>{/* Map content */}</ComposableMap>
When enabled, debug mode provides:
// Example debug output in console:
// πΊοΈ ComposableMap Render
// Owner Stack: ComposableMap <- App <- Router
// Props: { width: 800, height: 600, projection: "geoEqualEarth" }
debug={false} or omit the prop)REACT_SIMPLE_MAPS_DEBUG=false in production environmentsWe welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/vnedyalk0v/react19-simple-maps.git
cd react19-simple-maps
# Install dependencies
npm install
# Start development with watch mode
npm run dev
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Type checking
npm run type-check
# Linting
npm run lint
# Build the package
npm run build
npm run dev - Start development with watch modenpm run build - Build ESM output and type definitionsnpm run test - Run test suite with Vitestnpm run test:watch - Run tests in watch modenpm run test:ui - Run tests with UI interfacenpm run type-check - TypeScript type checkingnpm run lint - ESLint code lintingnpm run format - Format code with Prettiernpm run analyze - Bundle size analysisThe package uses Changesets for version management and automated publishing:
MIT licensed. Original work Copyright (c) Richard Zimerman 2017. Fork enhancements Copyright (c) Georgi Nedyalkov 2025. See LICENSE for more details.
Built with β€οΈ for the React community. Powered by React 19, TypeScript, and modern web standards.
FAQs
An svg map chart component built exclusively for React 19+ - Modern TypeScript-first library with cutting-edge React patterns
The npm package @vnedyalk0v/react19-simple-maps receives a total of 9,397 weekly downloads. As such, @vnedyalk0v/react19-simple-maps popularity was classified as popular.
We found that @vnedyalk0v/react19-simple-maps demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.

Product
Socket Firewall blocks malicious VS Code and Open VSX extensions before install, protecting developers from compromised editor marketplaces.