How To Create Maps With React And Leaflet

By Everett Quebral
Picture of the author
Published on
image alt attribute

How To Create Maps With React And Leaflet

Interactive maps are a powerful way to visualize location data in real time. Whether you're building a delivery tracker, travel guide, or data dashboard, integrating maps into your React app is easier than you think—with the help of Leaflet and React Leaflet.

In this post, we’ll walk through:

  • Why Leaflet is a great choice for maps
  • Setting up React Leaflet in a project
  • Displaying a map with custom markers
  • Adding popups, tile layers, and styling
  • Ideas for extending functionality with real-world data

Why Leaflet?

Leaflet is a lightweight, open-source JavaScript library for building mobile-friendly maps. It’s simple to get started, supports custom layers, and integrates well with React through the react-leaflet package.

Compared to heavier options like Google Maps, Leaflet is:

  • 🪶 Lightweight and performant
  • 🔓 Open-source (no API keys required)
  • 🌍 Supports OpenStreetMap and custom tiles
  • 🔧 Easily extendable with plugins

Step 1: Set Up the Project

Start with a new React project (or use an existing one):

npx create-react-app react-leaflet-map --template typescript
cd react-leaflet-map

Then install Leaflet and React Leaflet:

npm install leaflet react-leaflet

Leaflet’s CSS must be imported manually in your app:

// index.tsx or App.tsx
import 'leaflet/dist/leaflet.css'

Step 2: Display a Basic Map

Create a new component: components/MapView.tsx

import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'
import L from 'leaflet'

const position: [number, number] = [37.7749, -122.4194] // San Francisco

const MapView = () => {
  return (
    <MapContainer
      center={position}
      zoom={13}
      scrollWheelZoom={true}
      style={{ height: '100vh', width: '100%' }}
    >
      <TileLayer
        attribution='&copy; <a href="https://osm.org/copyright">OpenStreetMap</a>'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <Marker position={position}>
        <Popup>We are here!</Popup>
      </Marker>
    </MapContainer>
  )
}

export default MapView

Then render this component in App.tsx:

import MapView from './components/MapView'

function App() {
  return <MapView />
}

export default App

Step 3: Customizing the Marker

By default, Leaflet’s markers may appear broken in React because image paths don’t resolve automatically. Fix this by setting up a custom marker icon:

// fix for default icon rendering
import L from 'leaflet'
import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png'
import markerIcon from 'leaflet/dist/images/marker-icon.png'
import markerShadow from 'leaflet/dist/images/marker-shadow.png'

delete (L.Icon.Default.prototype as any)._getIconUrl

L.Icon.Default.mergeOptions({
  iconRetinaUrl: markerIcon2x,
  iconUrl: markerIcon,
  shadowUrl: markerShadow,
})

Add this to a leaflet.config.ts file and import it in your MapView or App.tsx.


Step 4: Rendering Dynamic Markers from Data

You can render multiple markers using an array of location objects:

const locations = [
  { id: 1, name: 'Golden Gate Bridge', coords: [37.8199, -122.4783] },
  { id: 2, name: 'Alcatraz Island', coords: [37.8267, -122.4230] },
]

{locations.map((loc) => (
  <Marker key={loc.id} position={loc.coords as [number, number]}>
    <Popup>{loc.name}</Popup>
  </Marker>
))}

📍 Use TypeScript tuples for position to ensure type safety with Leaflet's [number, number] format.


Step 5: Additional Features

Once the map is rendering, consider adding:

Tile Layers

Swap out default OpenStreetMap tiles:

<TileLayer
  url="https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
  attribution="Humanitarian OpenStreetMap"
/>

Circle or Polygon Overlays

<Circle center={position} radius={500} pathOptions={{ color: 'red' }} />

Fit map to markers

Use useMap() hook to auto-zoom or pan:

import { useMap } from 'react-leaflet'

function FitToBounds({ bounds }: { bounds: L.LatLngBoundsExpression }) {
  const map = useMap()
  useEffect(() => {
    map.fitBounds(bounds)
  }, [bounds])
  return null
}

Performance Tips

  • Use React.memo or dynamic imports to reduce render cost
  • Debounce or throttle marker updates for real-time tracking
  • Lazy-load map on scroll if it’s not above the fold
  • Store location data in context if shared across components

Final Thoughts

React Leaflet is a powerful and approachable tool for adding dynamic maps to your application. It provides all the benefits of Leaflet with a declarative React-friendly API.

By using this approach, you can:

  • Visualize real-world data with live updates
  • Create location-based apps and dashboards
  • Build experiences like route planners, real estate maps, or delivery tracking

This setup is just the beginning. With a bit more effort, you can integrate location search (via Nominatim), geocoding, clustering, and more.


Resources

Stay Tuned

Want to become a Next.js pro?
The best articles, links and news related to web development delivered once a week to your inbox.