Learn

GeoJSON with Leaflet.js

Leaflet's L.geoJSON() function turns a GeoJSON object into a map layer in four lines.

L.geoJSON takes a GeoJSON Feature, FeatureCollection, or bare geometry object and converts it to the appropriate Leaflet layer type: Marker for Points, Polyline for LineStrings, Polygon for Polygons, and so on. The result is added to the map just like any other layer — no parsing, no manual geometry translation.

Load and render

import L from 'leaflet'

const map = L.map('map').setView([51.5074, -0.1276], 12)
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map)

const data = await fetch('/features.geojson').then(r => r.json())
L.geoJSON(data).addTo(map)

L.map('map') attaches Leaflet to the element with id="map". setView takes [latitude, longitude] — note the order differs from GeoJSON coordinates, which use [longitude, latitude]. fetch returns a Response object; .then(r => r.json()) parses it to a plain JavaScript object before passing it to L.geoJSON.

The layer renders immediately with Leaflet's default styles: blue strokes for lines and polygons, blue markers for points.

Per-feature styling

L.geoJSON(data, {
  style: (feature) => ({
    color: feature.properties.type === 'park' ? '#2d9e6b' : '#3388ff',
    weight: 2,
    fillOpacity: 0.4,
  }),
}).addTo(map)

The style option receives each feature and returns a Path options object. color sets both stroke and fill colour unless fillColor is set separately. weight is stroke width in pixels. fillOpacity ranges from 0 (transparent) to 1 (opaque).

The style function only applies to vector layers (polygons, lines). For point features, use pointToLayer to create a custom marker instead.

Popups on click

L.geoJSON(data, {
  onEachFeature: (feature, layer) => {
    if (feature.properties?.name) {
      layer.bindPopup(feature.properties.name)
    }
  },
}).addTo(map)

onEachFeature runs once per feature after the layer is created. layer.bindPopup attaches a popup that opens when the user clicks the feature. The popup content is a string — you can pass HTML for richer content: layer.bindPopup('<strong>' + feature.properties.name + '</strong>').

The optional-chaining check (feature.properties?.name) guards against features with null properties, which RFC 7946 allows.

Filtering features

L.geoJSON(data, {
  filter: (feature) => feature.properties.visible !== false,
}).addTo(map)

The filter option runs before each feature is added. Return true to include the feature, false to skip it. This is applied at render time — it does not mutate the original data object. To update which features are visible, remove the layer and call L.geoJSON again with a new filter.

React-Leaflet

import { MapContainer, TileLayer, GeoJSON } from 'react-leaflet'
import type { FeatureCollection } from 'geojson'

const data: FeatureCollection = { type: 'FeatureCollection', features: [...] }

export function MyMap() {
  return (
    <MapContainer center={[51.5074, -0.1276]} zoom={12} style={{ height: 400 }}>
      <TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
      <GeoJSON data={data} />
    </MapContainer>
  )
}

react-leaflet's <GeoJSON> component wraps L.geoJSON and accepts the same options as props: style, onEachFeature, filter, pointToLayer. The FeatureCollection type is from the geojson npm package, which ships TypeScript declarations for all GeoJSON object types.

One caveat: <GeoJSON> does not update when the data prop changes reference. If your data changes at runtime, pass a new key prop to force a full remount:

<GeoJSON key={JSON.stringify(data)} data={data} />

Watch out: L.geoJSON accepts a plain JavaScript object, not a JSON string. If you're using fetch, call .then(r => r.json()) to parse before passing to Leaflet. Passing a string produces a silent empty layer.

Editing GeoJSON on a Leaflet map

Rendering GeoJSON in Leaflet is one line. Drawing and editing it — adding vertices, moving shapes, cutting holes — requires an editing layer. @element-editor/adapter-leaflet is an open-source MIT library that adds drawing and editing to an existing react-leaflet map without replacing your Leaflet setup.

Read the quickstart


For GeoJSON format reference, see What is GeoJSON?. For React-specific patterns, see GeoJSON with React.

Continue reading

Mike Acler

Mike Acler

Design engineer and creator of Element Editor, an open-source map drawing and GeoJSON editing library for React. Writes about web cartography and GIS tooling.