# API reference


**Site index:** [https://leaflet.2plot.dev/llms.txt](https://leaflet.2plot.dev/llms.txt) — every page on this site, as Markdown.  
**Network index:** [https://2plot.dev/llms.txt](https://2plot.dev/llms.txt) — The 2plot network; start here to discover sibling sites.  
**Sibling sites:** 13 more in The 2plot network — listed in the site index above.  
**Sitemap:** https://leaflet.2plot.dev/sitemap.xml  

## dash_leaflet2

### AttributionControl

AttributionControl adds an explicitly-controlled attribution box to the map. Place
it as a child of `dl2.Map` with `attributionControl=False` to take over from the
bundled default; both `position` and `prefix` are two-way (mutable from Python
callbacks). Pass `prefix=False` to hide the "Leaflet" link.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `position` | one of 'topleft', 'topright', 'bottomleft', 'bottomright' | 'bottomright' | Map control position. Default 'bottomright'. [MUTABLE] |
| `prefix` | string \| bool |  | HTML shown before the layer attributions. Default Leaflet's "Leaflet" link. Pass `False` (or empty string) to hide the prefix entirely. [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### BaseLayer

BaseLayer wraps a layer (typically a TileLayer) and registers it as a base layer in the
parent LayersControl. Bases are mutually exclusive (radio). Place it as a child of
LayersControl, with a single layer component (e.g. TileLayer) as its own child.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `checked` | bool | false | Initially selected base layer? Exactly one base is active at a time. |
| `children` | node |  | The Leaflet layer (typically a dl2.TileLayer) controlled by this entry. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `name` | string | 'Base' | Display name shown in the LayersControl (also the radio's identity). |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### Circle

Circle draws a circle with a radius in meters (it grows/shrinks with zoom). For a
fixed-pixel circle use CircleMarker. Place it as a child of Map. Wraps Leaflet 2's Circle.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `center` | tuple | [51.505, -0.09] | Center as [lat, lng]. [MUTABLE] |
| `children` | node |  | Popup / Tooltip children. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `color` | string | '#3388ff' | Stroke color. [MUTABLE] |
| `fillColor` | string |  | Fill color (defaults to stroke color). [MUTABLE] |
| `fillOpacity` | number | 0.2 | Fill opacity, 0..1. [MUTABLE] |
| `n_clicks` | number |  | Times the circle has been clicked. [READONLY] |
| `radius` | number | 100 | Radius in METERS (geographic). [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `weight` | number | 3 | Stroke width in pixels. [MUTABLE] |

### CircleMarker

CircleMarker draws a circle with a fixed pixel radius (it stays the same size at every
zoom). For a metric radius use Circle. Place it as a child of Map. Wraps Leaflet 2's
CircleMarker.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `center` | tuple | [51.505, -0.09] | Center as [lat, lng]. [MUTABLE] |
| `children` | node |  | Popup / Tooltip children. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `color` | string | '#3388ff' | Stroke color. [MUTABLE] |
| `fillColor` | string |  | Fill color (defaults to stroke color). [MUTABLE] |
| `fillOpacity` | number | 0.2 | Fill opacity, 0..1. [MUTABLE] |
| `interactive` | bool |  | Whether the circle captures pointer events (fires clicks, blocks the map click underneath). Set false for a non-interactive decoration / context overlay so it never intercepts clicks meant for the map. Construction-only. @default true |
| `n_clicks` | number |  | Times the marker has been clicked. [READONLY] |
| `radius` | number | 10 | Radius in PIXELS (fixed; does not scale with zoom). [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `weight` | number | 3 | Stroke width in pixels. [MUTABLE] |

### EasyButton

EasyButton adds a single-icon control to the map. Use it for quick map-level actions
(open a panel, locate, zoom-home, etc.); the click is reported back to Dash as n_clicks.
Icons come from Iconify (any of the 200k+ icons), e.g. "mdi:emoticon-happy-outline".
Place it as a child of dl2.Map.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `icon` | string | 'mdi:circle-medium' | Iconify icon name, e.g. "mdi:emoticon-happy-outline" or "mdi:crosshairs-gps". |
| `iconSize` | number | 18 | Icon size in pixels. |
| `n_clicks` | number | 0 | Number of times the button has been clicked. [READONLY] |
| `n_dblclicks` | number | 0 | Number of times the button has been double-clicked. [READONLY] |
| `position` | string | 'topleft' | "topleft" \| "topright" \| "bottomleft" \| "bottomright". |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `title` | string |  | Tooltip text shown on hover. |

### EditControl

EditControl renders a Leaflet draw/edit toolbar (native v2 — leaflet-draw is Leaflet
1-only). Place it as a child of dl2.Map. Shapes are kept in an internal FeatureGroup and
surfaced via the `geojson` prop. The Edit section appears only when at least one shape
exists. A contextual sub-toolbar appears while a tool is active (Finish / Delete last
point / Cancel during draw; Save / Cancel during edit; Clear all / Cancel during remove).

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `action` | dict |  | The most recent action, dash-leaflet-shaped:   {layer_type: 'polygon', type: 'created'\|'edited'\|'deleted', n_actions: int} Bumps every time something happens — useful as a sole Input for "anything changed". [READONLY] |
| `activeMode` | one of 'edit', 'remove' |  | The currently active edit/remove mode, or null. [READONLY] |
| `activeTool` | one of 'text', 'circle', 'marker', 'polyline', 'polygon', 'rectangle', 'circlemarker' |  | The currently active draw tool, or null. Emitted whenever a tool is activated or cleared — pages can use this to open a popover when the user clicks a draw icon (mirrors the `/easy-button` popover-on-button-click pattern). [READONLY] |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `draw` | objectOf |  | Per-tool enable/disable for the Draw section, e.g. {rectangle: False, marker: True}. Tools not listed default to enabled. |
| `drawToolbar` | dict |  | Python -> control: setting this prop activates a draw tool or dispatches an action on the currently active tool. Bump `n_clicks` to ensure the prop registers as changed. Shape: {mode?: tool name, action?: 'finish'\|'cancel'\|'delete last point', n_clicks: int}. [MUTABLE] |
| `edit` | objectOf |  | Per-mode enable/disable for the Edit section, e.g. {remove: False}. Modes not listed default to enabled. The Edit section only appears once at least one shape exists. |
| `editToolbar` | dict |  | Python -> control: enter edit/remove mode or dispatch save/cancel/clear-all. Bump `n_clicks` to ensure the prop changes. Shape: {mode?: 'edit'\|'remove', action?: 'save'\|'cancel'\|'clear all', n_clicks: int}. [MUTABLE] |
| `featureClick` | dict |  | The most recent feature click. Only fires while `editMode === 'edit'` — clicks on features in normal view mode do NOT emit this. The click is NOT propagated to the map (we set `bubblingMouseEvents: false`) so a Map.clickData callback only fires on empty-map clicks. Shape: {id, layerType, n_clicks}. [READONLY] |
| `featureUpdate` | dict |  | Python -> control: update or remove a single feature by its _dl2_id. Bump `n_clicks` each call to ensure the prop registers as changed. Shape:   {id, style?, properties?, remove?, n_clicks}   - style:      Leaflet path style options to apply via setStyle (color, weight, fillOpacity, ...)   - properties: merged into the feature's properties (e.g. {name: "Lighthouse"})   - remove:     drop the feature from the FeatureGroup [MUTABLE] |
| `geojson` | object |  | All currently drawn shapes as a GeoJSON FeatureCollection. [READONLY] |
| `lastAction` | object |  | Brief metadata for the most recent draw / delete event (legacy shape). [READONLY] |
| `measurementSystem` | one of 'metric', 'imperial' | 'metric' | Unit system for the live drawing previews — drives the radius readout in the circle tool and the area readout in the rectangle tool.  - 'metric' (default): meters / kilometers for distance; m² / hectares / km² for area. - 'imperial' (US customary): feet / miles for distance; ft² / acres / mi² for area.  Each formatter auto-picks the largest readable unit for the current magnitude (e.g. a 5 km radius reads "5.00 km"; a 50 m radius reads "50 m"). [MUTABLE] |
| `n_drawn` | number |  | Total shapes drawn since mount (decrements on delete). [READONLY] |
| `position` | string | 'topleft' | Control position: "topleft" \| "topright" \| "bottomleft" \| "bottomright". |
| `shapeOptions` | object | { color: '#2f9e44', weight: 3, fillOpacity: 0.2 } | Path style applied to drawn vectors (color, weight, fillOpacity, ...). |
| `showMeasurementTooltips` | bool | false | When true, every committed shape gets a permanent Leaflet tooltip showing its measured area (rectangle / circle / polygon) or length (polyline), formatted with the configured `measurementSystem`. [READONLY] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### FeatureGroup

FeatureGroup is like LayerGroup but extends `leaflet.FeatureGroup` — it can
emit a combined GeoJSON of its vector children and broadcasts a single
`click` event no matter which child was clicked. Use it when grouping
shapes you want to treat as one unit (typical companion for `EditControl`).
Wraps Leaflet 2's FeatureGroup.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `children` | node |  | Any number of layer children (Marker, Polygon, Circle, ...). |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `geojson` | object |  | Combined GeoJSON FeatureCollection of all children (vectors only). [READONLY] |
| `n_clicks` | number |  | Number of times any child layer has been clicked. [READONLY] |
| `n_layers` | number |  | Number of times the group's children were modified. [READONLY] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### FullScreenControl

FullScreenControl adds a single button to the map that toggles the map
container in/out of the browser's native fullscreen mode. Leaflet 2 doesn't
ship a fullscreen control — this maps the browser's `requestFullscreen()`
API onto a small `Control` subclass, matching the dash-leaflet (and
`Leaflet.fullscreen` plugin) API shape.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `fullscreen` | bool |  | Whether the map is currently in fullscreen mode. [READONLY] |
| `n_clicks` | number |  | Number of times the button has been clicked. [READONLY] |
| `position` | one of 'topleft', 'topright', 'bottomleft', 'bottomright' | 'topleft' | "topleft" \| "topright" \| "bottomleft" \| "bottomright". Default "topleft". [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `title` | string | 'Full Screen' | Tooltip text when entering fullscreen. Default "Full Screen". |
| `titleCancel` | string | 'Exit Full Screen' | Tooltip text when leaving fullscreen. Default "Exit Full Screen". |

### GeoJSON

GeoJSON renders a GeoJSON object — typically fed from a Python callback via the `data`
prop. Set `cluster=True` to collapse dense point sets via SuperCluster (the same backend
dash-leaflet 1's clustering uses). Custom `pointToLayer` / `clusterToLayer` JS strings
plus a `hideout` passthrough let you style features without round-tripping through Python.
Place it as a child of Map. Wraps Leaflet 2's GeoJSON layer.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `children` | node |  | Popup / Tooltip children bound to the whole layer. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `clickFeature` | object |  | `properties` of the most recently clicked feature. [READONLY] |
| `cluster` | bool | false | Turn on supercluster-based point clustering. Markers within `superClusterOptions.radius` pixels collapse into a single cluster bubble; zooming in expands them. Only point geometries cluster; vector features (LineString, Polygon) are passed through unchanged. |
| `clusterToLayer` | string |  | JavaScript source for a function that builds the layer shown in place of a SuperCluster cluster. Signature: `(feature, latlng, index, ctx) => Layer`. The default is a small DivIcon with the cluster's point count. |
| `data` | object |  | A GeoJSON FeatureCollection / Feature / geometry object. [MUTABLE] |
| `hideout` | objectOf |  | Arbitrary pass-through data made available to `pointToLayer` / `clusterToLayer` as `ctx.hideout`. Use it to ship colour maps, label dictionaries, or threshold values from Python without re-evaluating the JS function. [MUTABLE] |
| `n_clicks` | number |  | Number of times any feature has been clicked. [READONLY] |
| `pointToLayer` | string |  | JavaScript source for a function that converts an individual point feature into a layer. Signature: `(feature, latlng, ctx) => Layer`, where `ctx = { hideout, leaflet, map }`. Pass the function body as a string; it is wrapped in `new Function(...)` at construction time. The default uses the bundled DEFAULT_ICON. |
| `spiderfyOnMaxZoom` | bool | false | Reserved for future support — at max zoom, "spiderfy" overlapping markers into a ring so each is individually selectable. Currently a no-op (clicking the cluster at maxZoom still triggers zoomToBoundsOnClick). |
| `style` | object \| dict |  | Path style applied to all vector features, e.g. {color, weight, fillOpacity}. [MUTABLE]   Inline style for the root element. For Map, this is where you set height. |
| `superClusterOptions` | objectOf |  | Tuning for the underlying SuperCluster index: `{ radius, minPoints, maxZoom, minZoom, extent }`. Defaults: `{ radius: 80, minPoints: 2, maxZoom: 16, minZoom: 0, extent: 512 }`. See https://github.com/mapbox/supercluster#options for the full list. |
| `zoomToBoundsOnClick` | bool | true | If true, clicking a cluster fits the map to that cluster's children's bounds. Default true. |

### ImageOverlay

ImageOverlay drapes a single static image over a geographic bounding box. With `editable`
it gains a TextMarker-style transform control system: click to select, drag to move, a corner
handle to resize (scaling the bounds about the `anchor`), and a top handle to rotate (a visual
CSS rotation pivoting at the `anchor`). The white anchor dot marks where the image is pinned.
`bounds`, `rotation`, and `selected` round-trip back to Dash. Wraps Leaflet 2's ImageOverlay.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `alt` | string |  | Alt-text / title for the image element. |
| `anchor` | one of 'center', 'left', 'right', 'bottom', 'top', 'top-left', 'top-right', 'bottom-left' … | 'center' | Which point of the image is the rotation pivot + resize anchor + where the white anchor dot is drawn. One of center \| top-left \| top \| top-right \| left \| right \| bottom-left \| bottom \| bottom-right. @default "center". [MUTABLE] |
| `bounds` | objectOf | [[0, 0], [0, 0]] | Geographic bounds the image is stretched to, `[[south, west], [north, east]]`. Two-way when `editable`: dragging / resizing writes it back. [MUTABLE] |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `crossOrigin` | string |  | Adds the `crossOrigin` attribute to the img element. Pass "anonymous" to make the image load CORS-mode so canvas captures (map screenshots / html2canvas) can read the pixels. The host must answer with Access-Control-Allow-Origin or the image fails to load entirely — leave unset for hosts you don't control. "use-credentials" and "" are also valid. Construction-time only. |
| `editable` | bool | false | Enable the on-map transform controls: click to select, then drag to move, drag the corner handle to resize, and the top handle to rotate. @default false. |
| `interactive` | bool | false | If true, the image is wrapped in an interactive layer that fires click events. Forced on when `editable`. |
| `n_clicks` | number |  | Number of times the image has been clicked. [READONLY] |
| `n_transforms` | number |  | Bumped on each drag-move / resize commit. [READONLY] |
| `opacity` | number | 1 | Layer opacity, 0..1. [MUTABLE] |
| `rotation` | number | 0 | Visual rotation in degrees, CW. Applied as a CSS transform pivoting at the `anchor` (Leaflet's ImageOverlay has no native geographic rotation, so the image's `bounds` stay axis-aligned and only the rendered pixels rotate). The rotate handle writes it back. [MUTABLE] |
| `selected` | bool |  | Whether the transform chrome (outline + resize/rotate handles) is shown. Two-way: clicking the image selects it, a map-background click clears it. Only meaningful when `editable`. [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `url` | string | '' | URL of the image. [MUTABLE] |
| `zIndex` | number |  | Explicit z-index for the overlay pane. [MUTABLE] |

### KeyboardControl

KeyboardControl installs a window-level keyboard listener that drives map
rotation and pan. Place it as a child of <Map>. No DOM is rendered — it's a
pure side-effect component.
*
Default behavior:
  - Arrow keys rotate the map bearing (5° / press by default)
  - Cmd / Ctrl + Arrow keys pan the map (Leaflet's built-in arrow-key panning
    is suppressed by `map.keyboard.disable()` so the two don't both fire)
*
This makes the page feel like a flight sim: the arrows turn the camera, the
modifier is the "manual pan" escape hatch. Pages can flip the bindings by
passing a custom `keymap`.
*
Listens on `window`, not the map container — so a user pressing arrows while
the map div doesn't have focus still rotates. Pages with form inputs should
either set `enabled=false` while the form is focused or override the keymap.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `bearingStep` | number | 5 | Degrees of map bearing change per ArrowLeft / ArrowRight keypress. Default 5. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `enabled` | bool | true | Whether keyboard input is processed. When `false`, no key handler is installed. Useful for disabling controls while a modal/form is focused. [MUTABLE] |
| `keymap` | objectOf |  | Direction map: each property holds the action ('rotate-cw', 'rotate-ccw', 'pan-up', 'pan-down', 'pan-left', 'pan-right') triggered by a given key + modifier combination. Defaults to:    ArrowLeft        → rotate-ccw  (turn camera left)   ArrowRight       → rotate-cw   (turn camera right)   ArrowUp          → rotate-ccw  (same — feels natural for flight sims)   ArrowDown        → rotate-cw   Cmd\|Ctrl+ArrowLeft   → pan-left   Cmd\|Ctrl+ArrowRight  → pan-right   Cmd\|Ctrl+ArrowUp     → pan-up   Cmd\|Ctrl+ArrowDown   → pan-down  Pages can override individual entries (e.g. flight sims that want ArrowUp/Down to be throttle, not rotation) by passing a partial object. |
| `lastKey` | dict |  | The most recent key + action processed, as { key, action, modifier, ts }. [READONLY] |
| `n_pans` | number |  | Number of pan keypresses processed. [READONLY] |
| `n_rotations` | number |  | Number of bearing changes emitted (each rotate keypress increments). Useful as the sole Input for "did the user rotate?". [READONLY] |
| `panStep` | number | 80 | Pixels of map pan per Cmd+Arrow / Ctrl+Arrow keypress. Default 80 (matches Leaflet's own keyboard panOffset). |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### LayerGroup

LayerGroup bundles N layers so they can be added/removed together. Drop child
layers (Marker, Polygon, Circle, GeoJSON, ...) inside it; each is added to a
shared `leaflet.LayerGroup` instead of the map directly. Place it as a child
of `dl2.Map` — or of `dl2.Overlay` inside a LayersControl, to toggle the
whole group as one entry. Wraps Leaflet 2's LayerGroup.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `children` | node |  | Any number of layer children (Marker, Polygon, Circle, GeoJSON, ...). |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### LayersControl

LayersControl renders a Leaflet control that lets the user pick one of N base layers and
toggle M overlays. Place dl2.BaseLayer and dl2.Overlay as its children; LayersControl
itself must be a child of dl2.Map.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `activeBase` | string |  | Name of the active base layer. Two-way: reflects user choice + accepts callback. [MUTABLE] |
| `activeOverlays` | list of string |  | Names of currently visible overlays. Two-way. [MUTABLE] |
| `children` | node |  | BaseLayer + Overlay children. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `collapsed` | bool | true | If true, show only the toggle handle until the pointer enters. |
| `position` | string | 'topright' | "topright" \| "topleft" \| "bottomright" \| "bottomleft". |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### Map

Map is the root Leaflet 2 map container. It owns the Leaflet map instance and
provides it to child layers (TileLayer, Marker) through React context. Set the
height via the `style` prop.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `attributionControl` | bool | true | Whether Leaflet 2's built-in attribution control is added to the map. Default True (matches Leaflet's default). Set False when you want to mount a `dl2.AttributionControl` child and control position / prefix yourself — same convention as dash-leaflet's `attributionControl=False` + `dl.AttributionControl(...)` pairing. Constructor-only — changing it after the map is built has no effect. |
| `bearing` | number |  | Map rotation in degrees (CW from north). 0 = north up. Implemented as a CSS `transform: rotate()` on the leaflet map pane — the same technique `leaflet-rotate` uses on Leaflet 1.x. Leaflet 2 has no native rotation, so we build it the same way.  **Important caveat (CSS rotation, not coordinate-correct rotation):** Tiles, markers, polygons, and zoom math are computed in Leaflet's un-rotated coordinate space and the whole pane is then rotated visually. That works perfectly for read-only views and follow-camera flight/walk sims (you look at the map; the camera tracks the player). It breaks subtly for INTERACTIVE drawing at non-zero bearing — a click lands at the visually-rotated screen position, which is no longer the same latlng Leaflet would resolve from the bare event coords. For drawing, keep bearing = 0. A fully coordinate-correct rotation is a much larger project (essentially porting leaflet-rotate's coord math to v2).  [MUTABLE] |
| `boxZoom` | bool | true | Shift-drag box-zoom selection. Default true. [MUTABLE] |
| `center` | tuple | [51.505, -0.09] | Initial map center as [lat, lng]. Updating it from a callback re-centers the map. [MUTABLE] |
| `children` | node |  | Child layers (TileLayer, Marker, ...) rendered into this map. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `clickData` | dict |  | Data from the most recent map click: { latlng: [lat, lng] }. [READONLY] |
| `doubleClickZoom` | bool | true | Double-click-to-zoom. Default true. [MUTABLE] |
| `dragging` | bool | true | Mouse / pointer drag panning. Default true. [MUTABLE] |
| `flyTo` | dict |  | Python -> map: trigger a smooth viewport transition. The map calls the Leaflet 2 method indicated by `transition` and ignores the prop until `n_clicks` bumps again (matching `drawToolbar` / `editToolbar` / `featureUpdate` — needed so consecutive identical payloads still register as changes).  Shape:   {     transition: 'setView' \| 'flyTo' \| 'panTo' \| 'fitBounds' \| 'flyToBounds' \| 'panInsideBounds',     center?: [lat, lng],          # for setView / flyTo / panTo     zoom?:   number,              # optional zoom target (setView / flyTo)     bounds?: [[s, w], [n, e]],    # for fitBounds / flyToBounds / panInsideBounds     options?: object,             # passed straight to the Leaflet method                                   # (duration, easeLinearity, animate, paddingTopLeft, ...)     n_clicks: int,   }  `flyTo` / `flyToBounds` give the smooth glide-and-zoom motion; `setView` is instant; `panTo` glides without changing zoom. See the /flyto showcase. [MUTABLE] |
| `keyboard` | bool | true | Whether the map can be panned / zoomed with the keyboard (arrow keys + `+`/`-`). Default true. [MUTABLE] |
| `maxBounds` | tuple |  | Geographic bounds the map's view is constrained inside, as `[[south, west], [north, east]]`. Panning past the edges is bounced back. [MUTABLE] |
| `maxZoom` | number |  | Maximum zoom level the user can zoom in to. When a TileLayer also sets `maxZoom`, Leaflet uses the *smaller* of the two. [MUTABLE] |
| `minZoom` | number |  | Minimum zoom level the user can zoom out to. When a TileLayer also sets `minZoom`, Leaflet uses the *larger* of the two (the most restrictive value wins). [MUTABLE] |
| `n_moveend` | number |  | Counter bumped on every `moveend` event (a pan / flyTo / fit completes). `n_moveend < n_movestart` means a transition is currently running. [READONLY] |
| `n_movestart` | number |  | Counter bumped on every `movestart` event (a pan / flyTo / fit begins). Pair with `n_moveend` to drive a "flying…" indicator. [READONLY] |
| `pinchZoom` | bool | true | Pinch-to-zoom on touch devices. Default true. In Leaflet 1.x this was called `touchZoom`; in v2 it's `pinchZoom`. [MUTABLE] |
| `preferCanvas` | bool | false | If true, render all vector layers through the Canvas renderer (preferred for dense point sets). [READONLY] |
| `scrollWheelZoom` | bool | true | Mouse-wheel zoom. Default true. [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `tapHold` | bool |  | Mobile-safari tap-hold-to-contextmenu emulation. Defaults to true on mobile Safari only. [MUTABLE] |
| `viewport` | dict |  | Current view state, written back by the map on every moveend/zoomend as { center: [lat, lng], zoom, bearing, bounds: { north, south, east, west } }. Read this in callbacks. [READONLY] |
| `zoom` | number | 13 | Initial zoom level. Updating it from a callback changes the zoom. [MUTABLE] |
| `zoomControl` | bool | true | Whether Leaflet's built-in +/- zoom buttons control is added. Default true. Constructor-only — changing it after the map is built has no effect. |

### Marker

Marker displays an icon at a position and can host Popup/Tooltip children. The icon can
be the default pin, a custom image (`icon`), an `emoji`, or any Iconify icon (`iconify`,
e.g. "mdi:home"). Draggable markers write their new `position` back to Dash. Wraps
Leaflet 2's Marker. Place it as a child of Map.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `children` | node |  | Popup / Tooltip children bound to this marker. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `draggable` | bool | false | Whether the marker can be dragged with the pointer. [MUTABLE] |
| `emoji` | string |  | A single emoji to use as the marker, e.g. "🛥️". |
| `icon` | object |  | Custom image icon as Leaflet Icon options, e.g. {iconUrl, iconSize:[w,h], iconAnchor:[x,y]}. |
| `iconAnchor` | tuple |  | [x, y] icon anchor for emoji / iconify / iconOptions markers. Default bottom-center. |
| `iconColor` | string |  | CSS color for monochrome iconify icons. |
| `iconOptions` | object |  | Full Leaflet DivIcon options escape hatch ({html, className, iconSize, iconAnchor}). |
| `iconSize` | number | 32 | Pixel size for emoji / iconify markers. Default 32. |
| `iconify` | string |  | An Iconify icon name, e.g. "mdi:home" or "twemoji:sailboat" (loads from the Iconify API). |
| `n_clicks` | number |  | Number of times the marker has been clicked. [READONLY] |
| `n_drags` | number |  | Number of times the marker has been dragged. [READONLY] |
| `opacity` | number | 1 | Marker opacity, 0..1. [MUTABLE] |
| `popup` | string |  | Convenience popup text. For rich content, use a <Popup> child instead. |
| `position` | tuple | [51.505, -0.09] | Marker position as [lat, lng]. Updating it moves the marker; dragging writes it back. [MUTABLE] |
| `rotateWithMap` | bool | false | When `true`, the marker icon rotates together with the map — useful for vehicles, aircraft, walking characters, compass arrows, anything whose orientation is tied to the world. The icon's visual screen rotation is `bearing + rotationAngle`.  When `false` (default), the icon stays in a fixed screen orientation regardless of map bearing — useful for pins, labels, and the typical "marker should always look upright" case. The icon's visual screen rotation is just `rotationAngle`.  Implementation: when `false` we apply `rotationAngle - bearing` to the icon, which cancels the map pane's rotation contribution. When `true` we apply `rotationAngle` and let the pane's CSS rotation carry the icon. |
| `rotationAngle` | number | 0 | Marker rotation in degrees (CW from north). Useful for vehicle / aircraft / character sprites that need to point in a direction. Applied via a CSS `rotate` on the icon DOM. [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `tooltip` | string |  | Convenience tooltip text. For rich content, use a <Tooltip> child instead. |
| `zIndexOffset` | number | 0 | z-index offset relative to other markers. [MUTABLE] |

### MiniMap

MiniMap adds a small overview map in a corner of the main map. The overview tracks
the main map's center + zoom (with a configurable offset) and draws a rectangle showing
the main viewport. Click the corner toggle to collapse/expand. Place it as a child of
dl2.Map.
*
Native Leaflet 2 — `leaflet-minimap` (the Leaflet 1 plugin) does not run on v2.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `aimingRectOptions` | object | {         color: '#3388ff',         weight: 1,         fillColor: '#3388ff',         fillOpacity: 0.15,         interactive: false,     } | Leaflet path options for the aiming rectangle that shows the main map's viewport bounds on the minimap. Defaults to a translucent blue stroke. |
| `attribution` | string | '' | Attribution shown by the inner minimap. Empty by default — the main map already attributes. |
| `centerFixed` | tuple |  | When set to `[lat, lng]`, the inner minimap anchors on this point instead of tracking the main map's center. The aiming rectangle still reflects the main map's bounds — so the rectangle drifts off-minimap if the main map is panned far from the fixed point. Pass `null` (or omit) to follow the main map. Useful for "return-home" style affordances, where the minimap pins on a player / marker and clicking it (see `n_clicks`) snaps the main map back to them. [MUTABLE] |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `height` | number | 150 | Expanded height in pixels. Default 150. |
| `minimized` | bool |  | Whether the minimap starts (or currently is) minimized. Two-way: setting it from a Python callback collapses/expands the minimap; the user clicking the toggle button also writes it back. [MUTABLE] |
| `n_clicks` | number | 0 | Number of times the user has clicked anywhere on the inner minimap (excluding the corner expand/collapse toggle). Increments per click — pair with `prevent_initial_call=True` to use the minimap as a button. [READONLY] |
| `position` | one of 'topleft', 'topright', 'bottomleft', 'bottomright' | 'bottomright' | Control position: 'topleft' \| 'topright' \| 'bottomleft' \| 'bottomright'. Default 'bottomright'. |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `toggleDisplay` | bool | true | Show the [⤡] toggle button. Default true. |
| `url` | string | 'https://tile.openstreetmap.org/{z}/{x}/{y}.png' | Tile URL template for the inner minimap basemap. Defaults to OSM. |
| `width` | number | 150 | Expanded width in pixels. Default 150. |
| `zoomLevelOffset` | number | -5 | Zoom-level offset from the main map (negative = zoomed out further than the main). Default -5: a 150x150 minimap shows the main map's neighbourhood. |

### Overlay

Overlay wraps any layer and registers it as a toggleable overlay in the parent
LayersControl (checkbox). Place it as a child of LayersControl, with a single layer
component as its own child.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `checked` | bool | false | Initially checked? Overlays are independent. |
| `children` | node |  | The Leaflet layer (TileLayer, GeoJSON, Marker, ...) controlled by this entry. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `name` | string | 'Overlay' | Display name shown in the LayersControl (also the checkbox's identity). |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### Polygon

Polygon draws a filled, closed shape from a list of [lat, lng] points. Place it as a
child of Map. Wraps Leaflet 2's Polygon.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `children` | node |  | Popup / Tooltip children. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `color` | string | '#3388ff' | Stroke color. [MUTABLE] |
| `fillColor` | string |  | Fill color (defaults to stroke color). [MUTABLE] |
| `fillOpacity` | number | 0.2 | Fill opacity, 0..1. [MUTABLE] |
| `n_clicks` | number |  | Times the polygon has been clicked. [READONLY] |
| `opacity` | number | 1 | Stroke opacity, 0..1. [MUTABLE] |
| `positions` | list of tuple | [] | Ring vertices as a list of [lat, lng] points (auto-closed). [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `weight` | number | 3 | Stroke width in pixels. [MUTABLE] |

### Polyline

Polyline draws a multi-segment line from a list of [lat, lng] points. Place it as a
child of Map. Wraps Leaflet 2's Polyline.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `children` | node |  | Popup / Tooltip children. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `color` | string | '#3388ff' | Stroke color. [MUTABLE] |
| `dashArray` | string |  | Dash pattern, e.g. "5,10". [MUTABLE] |
| `interactive` | bool |  | Whether the line captures pointer events (fires clicks, blocks the map click underneath). Set false for a non-interactive decoration / context overlay so it never intercepts clicks meant for the map. Construction-only. @default true |
| `n_clicks` | number |  | Times the line has been clicked. [READONLY] |
| `opacity` | number | 1 | Stroke opacity, 0..1. [MUTABLE] |
| `positions` | list of tuple | [] | Vertices as a list of [lat, lng] points. [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `weight` | number | 3 | Stroke width in pixels. [MUTABLE] |

### Popup

Popup shows content in a balloon bound to its parent layer (Marker, Polygon, ...).
Children are rendered through a React portal, so any Dash component works as popup
content. Wraps Leaflet 2's Popup.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `autoClose` | bool |  | If true, opening a popup closes other popups. Leaflet defaults to true; set False to allow multiple popups open simultaneously. |
| `children` | node |  | Popup content — any Dash/HTML children, rendered live via a React portal. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `closeButton` | bool | true | Show the close (×) button. |
| `closeOnClick` | bool |  | If true, clicking the map closes the popup. Leaflet defaults to true; set False for form popups that should stay open while the user is interacting. |
| `maxWidth` | number | 300 | Max width in pixels. |
| `minWidth` | number | 50 | Min width in pixels. |
| `opened` | bool |  | Controlled open state — when set, the popup follows this prop (True → open, False → closed) instead of waiting for a click on the parent layer. [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |

### Rectangle

Rectangle draws an axis-aligned box from geographic bounds. Place it as a child of Map.
Wraps Leaflet 2's Rectangle.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `bounds` | tuple | [[0, 0], [0, 0]] | Geographic bounds as [[south, west], [north, east]]. [MUTABLE] |
| `children` | node |  | Popup / Tooltip children. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `color` | string | '#3388ff' | Stroke color. [MUTABLE] |
| `fillColor` | string |  | Fill color (defaults to stroke color). [MUTABLE] |
| `fillOpacity` | number | 0.2 | Fill opacity, 0..1. [MUTABLE] |
| `n_clicks` | number |  | Times the rectangle has been clicked. [READONLY] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `weight` | number | 3 | Stroke width in pixels. [MUTABLE] |

### ScaleControl

ScaleControl shows a metric and/or imperial scale bar in a map corner.
Wraps Leaflet 2's built-in `Control.Scale` (lives on the Control namespace
but not exported by the ESM — we reach in through `Control.Scale`).

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `imperial` | bool | false | Show imperial (mi/ft) bar. Default false. |
| `maxWidth` | number | 100 | Maximum bar width in pixels. Default 100. |
| `metric` | bool | true | Show metric (km/m) bar. Default true. |
| `position` | one of 'topleft', 'topright', 'bottomleft', 'bottomright' | 'bottomleft' | "topleft" \| "topright" \| "bottomleft" \| "bottomright". Default "bottomleft". [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `updateWhenIdle` | bool | false | Only redraw the bar when the map stops moving. Default false. |

### TextMarker

TextMarker is editable, draggable, styleable text placed on the map like a Marker. Give it
a `position` and `text`; drag to move, double-click to edit, and (when `selected`) use the
on-canvas resize / rotate handles and the contextual toolbar to restyle it. Position, text,
rotation, font size, and color all round-trip back to Dash. When `position` is omitted the
label spawns at the center of the current viewport. Place it as a child of dl2.Map.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `anchor` | one of 'center', 'left', 'right', 'bottom', 'top', 'top-left', 'top-right', 'bottom-left' … | 'center' | Which point of the text box sits on `position`. One of center \| top-left \| top \| top-right \| left \| right \| bottom-left \| bottom \| bottom-right. @default "center". |
| `backgroundColor` | string | 'transparent' | Box background behind the text ("transparent" for none). Editable from the toolbar. [MUTABLE] |
| `borderRadius` | number | 6 | Corner radius of the background pill in px. @default 6. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `color` | string | '#111827' | Text color (any CSS color / Mantine var). Editable from the toolbar. [MUTABLE] |
| `draggable` | bool | true | Whether the label can be dragged to a new position. @default true. |
| `editable` | bool | true | Whether double-click enters inline text edit. @default true. |
| `fontFamily` | string | 'system-ui, sans-serif' | Font family stack, e.g. "Inter, system-ui, sans-serif". [MUTABLE] |
| `fontSize` | number | 24 | Font size in screen px (the resize handle changes this). [MUTABLE] |
| `fontStyle` | one of 'normal', 'italic' | 'normal' | Font style: "normal" \| "italic". [MUTABLE] |
| `fontWeight` | string \| number | 600 | Font weight (400 / 600 / 700 / "bold" …). [MUTABLE] |
| `n_clicks` | number |  | Number of times the label has been clicked. [READONLY] |
| `n_drags` | number |  | Number of times the label has been dragged. [READONLY] |
| `n_edits` | number |  | Bumped on each committed text edit (fires a Dash Input even for identical text). [READONLY] |
| `opacity` | number | 1 | Caption opacity, 0..1 — fade the whole label in/out (e.g. keyframed transitions). @,default,1 [MUTABLE] |
| `padding` | number | 6 | Box padding in px (only visible when `backgroundColor` is set). [MUTABLE] |
| `position` | tuple |  | Text anchor as [lat, lng]. Dragging the label writes it back. When omitted, the label is created at the current center of the map viewport (and that position is emitted back so Python has it). [MUTABLE] |
| `referenceZoom` | number |  | The zoom level at which `fontSize` is the literal screen px (only used when `scaleWithZoom`). Defaults to the map's zoom when the label is created. [MUTABLE] |
| `rotateWithMap` | bool | false | When true the label rotates together with a rotated map (`Map.bearing`); when false (default) it stays upright on screen regardless of map bearing — like a Marker. |
| `rotation` | number | 0 | Rotation in degrees, CW from upright. The rotate handle changes this. [MUTABLE] |
| `scaleWithZoom` | bool | false | Geographic sizing. When false (default) the label is a constant screen-size HUD caption: `fontSize` is literal screen px at every zoom (like a Tooltip). When true the label scales with the map — its on-screen size grows/shrinks by 2^(zoom − referenceZoom) so it keeps a fixed *ground* footprint as the camera flies (like a polygon's edge). [MUTABLE] |
| `selected` | bool |  | Show selection chrome (resize / rotate handles + the style toolbar). Two-way: clicking the label sets it true and a map-background click clears it, so a host can also drive selection from the outside. [MUTABLE] |
| `showToolbar` | bool | true | Whether the contextual style toolbar is shown while selected. @default true. |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `text` | string | 'Text' | The caption string. Double-click the label to edit it inline; the committed text (on blur / Enter) is written back with `n_edits` bumped. [MUTABLE] |

### TileLayer

TileLayer loads and displays a raster tile basemap. Place it as a child of
Map. Wraps Leaflet 2's TileLayer.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `attribution` | string | '&copy; OpenStreetMap contributors' | Attribution HTML shown in the bottom-right of the map. |
| `bounds` | tuple |  | Geographic bounds outside of which no tiles are requested, as `[[south, west], [north, east]]`. Same as Leaflet's `LatLngBounds`. Cheaper than server-side 404s for out-of-area requests. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `crossOrigin` | string |  | Adds the `crossOrigin` attribute to every tile img element. Pass "anonymous" to make tile loads CORS-mode so canvas captures (map screenshots / html2canvas) can read the pixels. The tile host must answer with Access-Control-Allow-Origin or the tiles fail to load entirely — leave unset for hosts you don't control. "use-credentials" and "" are also valid. Construction-time only. |
| `detectRetina` | bool | false | If true, request tiles at 2x resolution on hi-DPI displays (loads twice as many tiles but renders sharper). |
| `errorTileUrl` | string |  | URL of an image shown in place of any tile that fails to load. A 1x1 transparent PNG data URL is the common "hide broken tiles" trick. |
| `maxNativeZoom` | number |  | Maximum zoom level that the tile source actually has tiles for. Leaflet upscales tiles from this zoom when the map zooms in past it (instead of 404-ing). Useful for overlays whose cache caps below the map's max zoom — e.g. USGS Hydro is only cached to z16; set `maxNativeZoom=16` and the z16 tile will be shown at z17/z18. |
| `maxZoom` | number | 19 | Maximum zoom level for this tile layer. |
| `minZoom` | number | 0 | Minimum zoom level at which this tile layer is visible. Below this zoom Leaflet stops requesting tiles entirely (no 404 thrash on out-of-range historical / harbor-cropped pyramids). Default 0. |
| `opacity` | number | 1 | Layer opacity, 0..1. [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `subdomains` | string \| list of string |  | Subdomains substituted into the URL `{s}` placeholder. Accepts an array like `['a','b','c']` or a string `'abc'` (each character is a subdomain). |
| `tms` | bool | false | If true, inverts Y coordinates so this layer works with TMS-shaped tile pyramids (Leaflet defaults to XYZ). |
| `url` | string | 'https://tile.openstreetmap.org/{z}/{x}/{y}.png' | Tile URL template, e.g. "https://tile.openstreetmap.org/{z}/{x}/{y}.png". Updating it swaps the basemap. [MUTABLE] |
| `zIndex` | number |  | Explicit z-index for the tile layer's DOM pane. Higher = renders on top. Useful when stacking multiple tile layers and DOM mount order alone is insufficient. [MUTABLE] |

### TileSelector

TileSelector adds a toggle button to the map. While active, the cursor becomes a
crosshair, a dashed outline tracks the tile under the cursor at the current map zoom,
and clicking a tile adds/removes it from the multi-select. Holding Shift while dragging
captures every tile inside the resulting box. Selections persist across zooms (each
tile is keyed by z/x/y). Place it as a child of dl2.Map.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `hoverColor` | string | '#fa5252' | Color of the hover outline. |
| `position` | string | 'topleft' | "topleft" \| "topright" \| "bottomleft" \| "bottomright". |
| `selectedColor` | string | '#228be6' | Stroke + fill color of selected-tile rectangles (and the box-drag preview). |
| `selectedTiles` | list of dict | [] | Currently selected tiles, each `{z, x, y, url, bounds: [s, w, n, e]}`. Two-way: clicks + shift-drag add/remove tiles (component → Python); Python callbacks can also push (e.g. a Clear button writes `[]`). [MUTABLE] |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
| `tileUrl` | string | 'https://tile.openstreetmap.org/{z}/{x}/{y}.png' | Tile URL template — same `{s}/{z}/{x}/{y}` form as a TileLayer URL. |

### Tooltip

Tooltip shows a small label on hover (or permanently), bound to its parent layer
(Marker, Polygon, ...). Children render through a React portal, so any Dash component
works as content. Wraps Leaflet 2's Tooltip.

| prop | type | default | description |
|---|---|---|---|
| `id` | string |  | The ID used to identify this component in Dash callbacks. |
| `children` | node |  | Tooltip content — any Dash/HTML children, rendered live via a React portal. |
| `className` | string |  | Often-used CSS class name(s) for the root element. |
| `direction` | string | 'auto' | Placement: "right" \| "left" \| "top" \| "bottom" \| "center" \| "auto". |
| `opacity` | number | 0.9 | Tooltip opacity, 0..1. |
| `permanent` | bool | false | If true, the tooltip stays open instead of showing only on hover. |
| `style` | dict |  | Inline style for the root element. For Map, this is where you set height. |
