From 1c6e0926980eae423cbfda1e25618a012b8342b1 Mon Sep 17 00:00:00 2001 From: adarshsm <24850536+adarshsm@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:28:38 +0530 Subject: [PATCH] Add a popup argument to TopoJson TopoJson takes a tooltip but no popup, so per-feature popups need a separate GeoJsonPopup(...).add_to(topojson) call. Accept popup the same way tooltip is accepted: a GeoJsonPopup or Popup is added as a child and a string is wrapped in a Popup. Closes #1461 Co-Authored-By: Claude Opus 5.5 --- folium/features.py | 8 ++++++++ tests/test_features.py | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/folium/features.py b/folium/features.py index 587f5e053b..829cb44d28 100644 --- a/folium/features.py +++ b/folium/features.py @@ -972,6 +972,9 @@ class TopoJson(JSCSSMixin, Layer): tooltip: GeoJsonTooltip, Tooltip or str, default None Display a text when hovering over the object. Can utilize the data, see folium.GeoJsonTooltip for info on how to do that. + popup: GeoJsonPopup, Popup or str, default None + Show a popup when clicking on the object. Pass a GeoJsonPopup to show + a different popup for each feature. Examples -------- @@ -1032,6 +1035,7 @@ def __init__( show: bool = True, smooth_factor: Optional[float] = None, tooltip: Union[str, Tooltip, None] = None, + popup: Union[str, Popup, None] = None, ): super().__init__(name=name, overlay=overlay, control=control, show=show) self._name = "TopoJson" @@ -1059,6 +1063,10 @@ def __init__( self.add_child(tooltip) elif tooltip is not None: self.add_child(Tooltip(tooltip)) + if isinstance(popup, (GeoJsonPopup, Popup)): + self.add_child(popup) + elif popup is not None: + self.add_child(Popup(popup)) def style_data(self) -> None: """Applies self.style_function to each feature of self.data.""" diff --git a/tests/test_features.py b/tests/test_features.py index e41e0e8337..2cf793cc6e 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -86,6 +86,33 @@ def test_topojson_non_collection_geometry_detail(detail_type): assert "name" in map_.get_root().render() +@pytest.mark.parametrize( + "popup", [folium.GeoJsonPopup(fields=["name"]), Popup("hello"), "hello"] +) +def test_topojson_popup(popup): + """TopoJson accepts a popup, like GeoJson does.""" + topology = { + "type": "Topology", + "objects": { + "shape": { + "type": "Polygon", + "arcs": [[0]], + "properties": {"name": "A"}, + } + }, + "arcs": [[[0, 0], [1, 0], [0, 1], [-1, -1]]], + "transform": {"scale": [1, 1], "translate": [0, 0]}, + } + + map_ = folium.Map() + topojson = folium.TopoJson(topology, "objects.shape", popup=popup).add_to(map_) + + children = list(topojson._children.values()) + assert len(children) == 1 + assert isinstance(children[0], (folium.GeoJsonPopup, Popup)) + assert f"{topojson.get_name()}.bindPopup(" in map_.get_root().render() + + @pytest.fixture def tmpl(): yield ("""