Skip to content

MapView (Experimental)

MapView renders an interactive Leaflet map with optional CDN asset injection.

Import

from faststrap import MapView

Basic Usage

MapView(
    latitude=6.5244,
    longitude=3.3792,
    zoom=12,
    popup_text="Lagos",
)

Key Options

Parameter Type Default Description
latitude float required Center latitude. Must be between -90 and 90.
longitude float required Center longitude. Must be between -180 and 180.
zoom int 13 Leaflet zoom level, 0 to 22.
height str "320px" Map container height.
width str "100%" Map container width.
marker bool True Place a marker at the center coordinate.
popup_text str \| None None Optional marker popup text.
map_id str \| None None Explicit DOM ID. Auto-generated when omitted.
include_assets bool True Inject Leaflet CSS/JS from CDN.
tiles_url str OpenStreetMap tiles Leaflet tile URL template.
attribution str OpenStreetMap attribution Tile attribution HTML.
leaflet_css_url str Leaflet CDN CSS Override CSS URL.
leaflet_js_url str Leaflet CDN JS Override JS URL.
**kwargs Any Extra container attributes.

Reusing Leaflet Assets

If the page already loads Leaflet once, set include_assets=False for additional maps:

MapView(
    latitude=40.7128,
    longitude=-74.0060,
    include_assets=False,
)

Size Implication

Leaflet is CDN-first in this component, so Faststrap wheel size does not increase unless you choose to vendor assets yourself.

API Reference

faststrap.components.display.map_view.MapView(*, latitude, longitude, zoom=13, height='320px', width='100%', marker=True, popup_text=None, map_id=None, include_assets=True, tiles_url=DEFAULT_TILES_URL, attribution=DEFAULT_ATTRIBUTION, leaflet_css_url=LEAFLET_CSS_URL, leaflet_js_url=LEAFLET_JS_URL, **kwargs)

Render an interactive Leaflet map.

Notes: - Experimental API; may evolve before v0.6.0. - Leaflet is CDN-first by default to avoid increasing package size.

Source code in src/faststrap/components/display/map_view.py
@experimental
@register(category="display", requires_js=True)
def MapView(
    *,
    latitude: float,
    longitude: float,
    zoom: int = 13,
    height: str = "320px",
    width: str = "100%",
    marker: bool = True,
    popup_text: str | None = None,
    map_id: str | None = None,
    include_assets: bool = True,
    tiles_url: str = DEFAULT_TILES_URL,
    attribution: str = DEFAULT_ATTRIBUTION,
    leaflet_css_url: str = LEAFLET_CSS_URL,
    leaflet_js_url: str = LEAFLET_JS_URL,
    **kwargs: Any,
) -> tuple[Any, ...]:
    """Render an interactive Leaflet map.

    Notes:
    - Experimental API; may evolve before v0.6.0.
    - Leaflet is CDN-first by default to avoid increasing package size.
    """
    if not (-90 <= latitude <= 90):
        msg = f"latitude must be between -90 and 90, got {latitude}"
        raise ValueError(msg)
    if not (-180 <= longitude <= 180):
        msg = f"longitude must be between -180 and 180, got {longitude}"
        raise ValueError(msg)
    if zoom < 0 or zoom > 22:
        msg = f"zoom must be between 0 and 22, got {zoom}"
        raise ValueError(msg)

    resolved_map_id = map_id or f"faststrap-map-{uuid4().hex[:8]}"
    user_cls = kwargs.pop("cls", "")

    container_attrs: dict[str, Any] = {
        "id": resolved_map_id,
        "cls": merge_classes("faststrap-map-view rounded border", user_cls),
        "style": f"height: {height}; width: {width};",
        "role": "region",
        "aria_label": "Interactive map",
    }
    container_attrs.update(convert_attrs(kwargs))
    map_container = Div(**container_attrs)

    marker_block = ""
    if marker:
        marker_block = f"""
const marker = L.marker([{latitude}, {longitude}]).addTo(map);
"""
        if popup_text:
            marker_block += f"marker.bindPopup({json.dumps(popup_text)});"

    # fmt: off
    init_script = Script(NotStr(f"""
if (window.L) {{
  const map = L.map({resolved_map_id!r}).setView([{latitude}, {longitude}], {zoom});
  L.tileLayer({tiles_url!r}, {{ attribution: {attribution!r} }}).addTo(map);
  {marker_block}
}} else {{
  console.warn("Faststrap MapView: Leaflet was not loaded.");
}}
"""))
    # fmt: on

    if include_assets:
        return (
            Link(rel="stylesheet", href=leaflet_css_url),
            Script(src=leaflet_js_url),
            map_container,
            init_script,
        )
    return (map_container, init_script)