dash-leaflet2
dash-leaflet2 — Leaflet 2 maps for Dash
Leaflet 2-native mapping components for Plotly Dash 4.
No react-leaflet · unified Pointer Events · BlanketOverlay canvas/WebGL layers · ES6-class subclassing · ResizeObserver sizing · map rotation · liquid-glass theme · full Dash callback interoperability.
Documentation · Discord · YouTube · GitHub
Live at leaflet.2plot.dev — every map on the docs site is a running Dash app.
Maintained by Pip Install Python LLC.
Overview
dash-leaflet is frozen on react-leaflet → Leaflet 1.9.
react-leaflet has no Leaflet 2 line, and its architecture is built around Leaflet 1.x's
context and lifecycle model — so a Leaflet-2-native component cannot ride react-leaflet.
dash-leaflet2 wraps Leaflet 2 core directly through a small React-context bridge.
That sheds the entire react-leaflet abstraction layer and unlocks v2's headline features:
- Unified Pointer Events — one event model for mouse, touch and stylus. The Leaflet
event's
.originalEventis a nativePointerEvent, sopointerType,pressureandtiltX/tiltYreach your Python callbacks BlanketOverlaycanvas / WebGL layers — draw your own renderer across the whole viewport instead of fighting the DOM layer system- ES6-class subclassing — extend Leaflet 2 classes in plain JS and mount the result as a Dash component
ResizeObserversizing — no more grey tiles when a map is born inside a hidden tab, accordion or drawer- Map rotation —
bearingas a first-class, two-way prop, with a keyboard control - Liquid-glass theme — tooltips, popups, the zoom bar and attribution use
color-mix()+backdrop-filter, so they read correctly in light and dark mode
The package ships the compiled JS bundle — Leaflet 2, the marker images and the theme CSS
all live inside dash_leaflet2.js. A normal pip install needs no Node and no
external_scripts.
Status: alpha. This tracks Leaflet
2.0.0-alpha.1, so the0.xline is itself alpha and APIs will move until v2 leaves alpha upstream. See CHANGELOG.md for what's shipped, fixed and known-broken.
Watch the introduction
Drone tracking, image overlays and map packages, built with this library.
Installation
pip install dash-leaflet2
Requires dash>=4.1. See Dash compatibility for the tested matrix.
Quick Start
from dash import Dash, Input, Output, callback, html
import dash_leaflet2 as dl2
app = Dash(__name__)
app.layout = html.Div([
dl2.Map(
id="map",
center=[28.0206, -97.0544],
zoom=12,
style={"height": "70vh"},
children=[
dl2.TileLayer(url="https://tile.openstreetmap.org/{z}/{x}/{y}.png"),
dl2.Marker(
id="pin",
position=[28.0206, -97.0544],
draggable=True,
children=dl2.Tooltip("Drag me"),
),
],
),
html.Pre(id="out"),
])
@callback(Output("out", "children"), Input("pin", "position"))
def show(position):
return f"marker at {position}"
if __name__ == "__main__":
app.run(debug=True)
Drag the pin and position round-trips to Python. No JS, no external_scripts, no
Leaflet CSS link — the bundle carries all of it.
Documentation
Full documentation, with a live interactive demo on every page:
📚 leaflet.2plot.dev
Every page also serves /<page>/llms.txt — the prose plus the complete example source,
directive-expanded and ready to paste into a chat window.
You can also run the docs site locally:
pip install -r requirements.txt
# markdown2dash pins gunicorn<22, against the CVE-driven gunicorn>=23 floor
# in requirements.txt. Its real dependencies are listed there, so it installs
# without its dependency graph — the docs pages need it.
pip install --no-deps markdown2dash==0.1.2
python run.py # open http://127.0.0.1:8050
…or the standalone component harness, which exercises the compiled dl2.* surface
without the docs shell:
python usage.py # open http://127.0.0.1:8060
Components
26 components, all loading from the single bundled JS file.
Core
| Component | What it is |
|---|---|
Map |
The root container. Owns the Leaflet 2 map instance and provides it to children through React context. Two-way center / zoom / bearing / bounds, plus the full pro-prop surface (minZoom, maxBounds, zoomSnap, inertia, …). |
TileLayer |
Raster tile basemap. minZoom, bounds, errorTileUrl, zIndex, subdomains, detectRetina, tms, crossOrigin; opacity and zIndex are [MUTABLE]. |
Marker |
Icon at a position, hosting Popup / Tooltip children. Icon modes: default pin, custom image, emoji, or any Iconify icon. Draggable markers write position back to Dash. |
Popup / Tooltip |
Balloon and hover label bound to a parent layer. Children render through a React portal, so any Dash component works as content. |
Layers
| Component | What it is |
|---|---|
GeoJSON |
Renders a GeoJSON object from a callback. cluster=True collapses dense point sets via SuperCluster; custom pointToLayer / clusterToLayer JS strings supported. |
LayerGroup |
Bundles N layers so they add and remove together. |
FeatureGroup |
Like LayerGroup, but emits a combined GeoJSON of its vector children and broadcasts one click regardless of which child was hit. |
ImageOverlay |
Drapes a static image over a bounding box. With editable, gains click-to-select, drag-to-move, corner-resize and rotate handles; bounds / rotation / selected round-trip. |
Vectors
| Component | What it is |
|---|---|
Circle |
Radius in meters — grows and shrinks with zoom. |
CircleMarker |
Radius in pixels — constant size at every zoom. |
Polyline |
Multi-segment line from [lat, lng] points. |
Polygon |
Filled closed shape from [lat, lng] points. |
Rectangle |
Axis-aligned box from geographic bounds. |
Controls
| Component | What it is |
|---|---|
LayersControl + BaseLayer / Overlay |
Base-layer radio group and overlay checkboxes. A custom implementation — Leaflet 2's bundled Layers class is not exported by its ESM. |
EditControl |
Native v2 draw/edit toolbar (leaflet-draw is Leaflet-1-only and DOA on v2). Marker / polyline / polygon / rectangle / circle / delete, round-tripping geojson, n_drawn and lastAction. |
AttributionControl |
Explicit attribution box. position and prefix are both [MUTABLE]; prefix=False hides the Leaflet link. |
ScaleControl |
Metric and/or imperial scale bar. |
FullScreenControl |
Toggles the map container through the browser's native requestFullscreen(). Leaflet 2 ships no fullscreen control. |
MiniMap |
Corner overview map tracking the main map's center and zoom, with a viewport rectangle and a collapse toggle. |
EasyButton |
Single-icon control for a map-level action; the click arrives as n_clicks. Icons from Iconify. |
KeyboardControl |
Window-level key listener driving rotation and pan. Renders no DOM — a pure side-effect component. |
TileSelector |
Turns the map into a tile picker: click or shift-drag to select tiles, which round-trip as {z, x, y, url, bounds}. |
TextMarker |
Editable, draggable, styleable text on the map. Double-click to edit; on-canvas resize / rotate handles and a contextual toolbar when selected. |
Full prop tables are generated into each dash_leaflet2/<Component>.py docstring by
dash-generate-components, and rendered on every documentation page.
The data boundary
- Two-way props are marked in the docstrings.
[MUTABLE]means Python callbacks can push the value into the map;[READONLY]means the map writes it back.Map.center,Map.zoom,Map.bearing,Marker.position,TileSelector.selectedTiles,ImageOverlay.boundsandEditControl.geojsonall round-trip in both directions. - Events are props, not a separate channel. Clicks land as
n_clicks, drags as an updatedposition, draws asgeojson+lastAction— so a plain@callbackis the whole integration. - Pointer events carry v2's extra data. Pointer props report
pointerType,pressureandtiltX/tiltYfrom the nativePointerEvent, which Leaflet 1 could not express. - Only JSON crosses the boundary. Tiles, canvas bitmaps and the Leaflet instances themselves stay in the browser.
Dash compatibility
dash-leaflet2 targets Dash 4.1 and up. That range is verified, not assumed —
scripts/compat_matrix.py builds a throwaway virtualenv per Dash version, installs the
full documentation site into each, and runs the smoke suite there:
python scripts/compat_matrix.py # 4.1.0, 4.2.0, 4.3.0, 4.4.1
python scripts/compat_matrix.py 4.4.1 --backends flask fastapi
python scripts/compat_matrix.py --browser # + Playwright console-error sweep
Results land in COMPATIBILITY.md. The per-version harness is
scripts/smoke_test.py, which also runs standalone:
python scripts/smoke_test.py
It checks that every markdown page registered a route with no duplicate paths, that every
page layout builds and survives Dash's JSON encoder, and that every route plus
/_dash-layout, /_dash-dependencies, /healthz, /llms.txt, /robots.txt and
/sitemap.xml answers over the backend's test client. No socket, no browser.
Development
# Install dependencies
npm install # TypeScript + webpack toolchain
pip install -r requirements.txt
# Build the JS bundle + regenerate the Python wrappers
npm run build # webpack UMD bundle + dash-generate-components
npm run build:js # webpack only (after .tsx edits)
npm run build:backends # regenerate Python classes only (after prop changes)
npm run watch # JS-only rebuild loop
# Run
python run.py # documentation site → http://127.0.0.1:8050
python usage.py # component harness → http://127.0.0.1:8060
# Test
python scripts/smoke_test.py
# Build a distribution
python -m build --wheel
- TypeScript source of truth is
src/ts/—components/holds the public components;icons.ts,theme.css,useLayer.tsandlayersControl-shared.tsare the shared plumbing;types/leaflet.d.tsis our ambient declaration (Leaflet 2 ships no types). - After editing
src/ts/components/*.tsxyou mustnpm run build— the Python classes and the JS bundle are generated artifacts. - The built bundle and generated wrappers are committed, so
pip install -e .works without npm. dash_leaflet2/__init__.pyis hand-maintained (it registers_js_dist);dash-generate-componentsdoes not regenerate it.- Defaults go in destructured default parameters, never
Component.defaultProps(React 18.3 deprecation warning;react-docgen@5reads both, so the defaults survive). - Keep the version in sync across
package.json,pyproject.tomlandlib/constants.pywhen cutting a release.
Documentation site
Each page is a docs/<slug>/<slug>.md with frontmatter plus a docs/<slug>/example.py
exporting a component. pages/markdown.py walks them and registers each as a Dash page;
.. exec:: embeds the live demo, .. source:: renders the example source, and
.. kwargs:: generates the prop table. Adding a page is two files and no routing code.
The deployed site at leaflet.2plot.dev also runs as a
2plot network satellite — ad slots, traffic rollups, Clerk sign-in and
an admin page-visibility board. Every one of those is dormant without its environment
keys, so a local python run.py is just the docs. See DEPLOYMENT.md.
Requirements
- Python >= 3.9 (the documentation site itself needs >= 3.10 — see below)
- Dash >= 4.1
- Node.js >= 16 — only to rebuild the JS bundle
The package needs only Python 3.9+ and Dash 4.1+; every combination in
that range is verified in CI. Running the documentation site from source
additionally needs Python 3.10+, because python-frontmatter imports
typing.TypeGuard. That floor does not apply to pip install dash-leaflet2.
Leaflet 2 notes
Leaflet 2 is a genuine break from 1.x, and these cost real debugging time:
- The version string is
2.0.0-alpha.1, with the dot. The dotless form 404s on unpkg. - The UMD build exposes
window.leaflet, notwindow.L— theLglobal is gone. - There are no lowercase factory functions. Use
new Marker(...), notL.marker(...). - v2 fires pointer events (
pointermove/pointerdown), notmousemove/mousedown. - Canvas-clear bug:
BlanketOverlay._onMoveEnd()draws and then calls_resizeContainer(), which setscanvas.widthand wipes the bitmap — so the Canvas renderer goes blank after pan/zoom. We re-issue a redraw on the next animation frame aftermoveend/zoomend. The SVG renderer is unaffected. - Default marker icons need explicit wiring when bundled: v2's CSS-based icon-path
detection fails, and
Marker's default icon is a shared instance created at module-load time. All of it is handled insrc/ts/icons.ts.
The documentation site covers each of these with a live page.
Community & support
Come build with us:
- 💬 Discord — discord.gg/WEnZR35mrK
- ▶️ YouTube — @2plotai
- 🐛 Issues — github.com/pip-install-python/dash-leaflet2/issues
More from Pip Install Python LLC
dash-leaflet2 is one of several tools built and maintained by Pip Install Python LLC:
| Project | What it is |
|---|---|
| 📚 Pip Install Python | Open-source documentation index for the Python & Dash ecosystem |
| 🔀 2plot.ai | Frame-accurate NLE timeline & scene compositor for Dash |
| 🛍️ PiratesBargain.com | E-commerce / digital commerce |
| 🧠 ai-agent.buzz | Infinite AI canvas |
| 🎬 2plot.media | Videography application |
License
MIT — see LICENSE. Built by Pip Install Python LLC to bring a generation-ahead mapping stack into the Dash framework.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dash_leaflet2-0.2.2.tar.gz.
File metadata
- Download URL: dash_leaflet2-0.2.2.tar.gz
- Upload date:
- Size: 154.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a385d84a6355a59acbe477fa5b005fd1663ac0034ac723589a29ef61e7f4036
|
|
| MD5 |
53b6bc6b5a5ce665505fd620fdac8380
|
|
| BLAKE2b-256 |
787d717b23289c504a3e3ca246f975162fcc22177a00e4c4b6dd1f0e073e1a57
|
Provenance
The following attestation bundles were made for dash_leaflet2-0.2.2.tar.gz:
Publisher:
release.yml on pip-install-python/dash-leaflet2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dash_leaflet2-0.2.2.tar.gz -
Subject digest:
0a385d84a6355a59acbe477fa5b005fd1663ac0034ac723589a29ef61e7f4036 - Sigstore transparency entry: 2351066408
- Sigstore integration time:
-
Permalink:
pip-install-python/dash-leaflet2@c22465558afe29796e81af8189281238ff1af7f7 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/pip-install-python
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c22465558afe29796e81af8189281238ff1af7f7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dash_leaflet2-0.2.2-py3-none-any.whl.
File metadata
- Download URL: dash_leaflet2-0.2.2-py3-none-any.whl
- Upload date:
- Size: 152.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42f983c6a8ff58900cb7bb14108183263d9836d97dd3d97d43472c10a4f221e8
|
|
| MD5 |
38883c2eaea8b498799dbdca6d5c8957
|
|
| BLAKE2b-256 |
2efd1d7baddbdd99c2ec2777434b071f119e8468a19d2b1d59285f35fabf7b33
|
Provenance
The following attestation bundles were made for dash_leaflet2-0.2.2-py3-none-any.whl:
Publisher:
release.yml on pip-install-python/dash-leaflet2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dash_leaflet2-0.2.2-py3-none-any.whl -
Subject digest:
42f983c6a8ff58900cb7bb14108183263d9836d97dd3d97d43472c10a4f221e8 - Sigstore transparency entry: 2351066808
- Sigstore integration time:
-
Permalink:
pip-install-python/dash-leaflet2@c22465558afe29796e81af8189281238ff1af7f7 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/pip-install-python
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c22465558afe29796e81af8189281238ff1af7f7 -
Trigger Event:
push
-
Statement type: