Add a Geocoder Search Control to Leaflet
This example adds a search control to the top right corner of a Leaflet map using the leaflet-control-geocoder plugin. Searching for an address calls the Maptoolkit Geocoding API and centers the map on the result. Try searching for Sillgasse.
Dependencies: leaflet-control-geocoder
let map = L.map("map").setView([47.26816, 11.40037], 13);
L.tileLayer("https://rtc-cdn.maptoolkit.net/rtc/maptoolkit-maptoolkit.summer/{z}/{x}/{y}{ratio}.png?api_key=YOUR_API_KEY", {
ratio: L.Browser.retina ? "@2x" : "",
maxZoom: 18,
attribution: "© <a href='https://www.maptoolkit.com' target='_blank'>Maptoolkit</a> © <a href='https://www.openstreetmap.org/copyright' target='_blank'>OSM</a>",
}).addTo(map);
L.Control.geocoder({
geocoder: {
geocode: (query, callback, context) => {
fetch(`https://geocoder.maptoolkit.net/search?q=${encodeURIComponent(query)}&language=en&api_key=YOUR_API_KEY`)
.then((r) => r.json())
.then((result) => {
callback.call(context, result.map((e) => ({
bbox: [[e.boundingbox[0], e.boundingbox[2]], [e.boundingbox[1], e.boundingbox[3]]],
center: [e.lat, e.lon],
name: e.display_name,
})));
});
},
suggest: function(query, callback, context) {
return this.geocode(query, callback, context);
},
}
}).addTo(map);<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.css" />
<script src="https://cdn.jsdelivr.net/npm/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet-control-geocoder/dist/Control.Geocoder.css" />
<style>
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
#map { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
let map = L.map("map").setView([47.26816, 11.40037], 13);
L.tileLayer("https://rtc-cdn.maptoolkit.net/rtc/maptoolkit-maptoolkit.summer/{z}/{x}/{y}{ratio}.png?api_key=YOUR_API_KEY", {
ratio: L.Browser.retina ? "@2x" : "",
maxZoom: 18,
attribution: "© <a href='https://www.maptoolkit.com' target='_blank'>Maptoolkit</a> © <a href='https://www.openstreetmap.org/copyright' target='_blank'>OSM</a>",
}).addTo(map);
L.Control.geocoder({
geocoder: {
geocode: (query, callback, context) => {
fetch(`https://geocoder.maptoolkit.net/search?q=${encodeURIComponent(query)}&language=en&api_key=YOUR_API_KEY`)
.then((r) => r.json())
.then((result) => {
callback.call(context, result.map((e) => ({
bbox: [[e.boundingbox[0], e.boundingbox[2]], [e.boundingbox[1], e.boundingbox[3]]],
center: [e.lat, e.lon],
name: e.display_name,
})));
});
},
suggest: function(query, callback, context) {
return this.geocode(query, callback, context);
},
}
}).addTo(map);
</script>
</body>
</html>Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.
How it works
leaflet-control-geocoder supplies the search box and expects a geocoder object with a
geocode method, so this example supplies one that calls Maptoolkit instead of the plugin’s
default provider.
The response is Nominatim-shaped, which explains several details that
otherwise look arbitrary. lat and lon come back as strings, not numbers, so they need
coercing before a map will accept them. display_name is the full formatted address.
boundingbox is [south, north, west, east], also as strings, which is a different order
from the [west, south, east, north] that most GeoJSON tooling expects.
The query has to be URL-encoded. encodeURIComponent is not optional: an address with a
comma or an ampersand truncates the query without it.
The callback needs bbox as [[south, west], [north, east]], which is why the four
boundingbox entries are reshuffled rather than passed straight through.
suggest delegates to geocode, so typing queries the service on each keystroke. If you
are watching request counts, debounce it or drop suggest entirely.
Next steps
Search is half of geocoding. Reverse geocoding turns a coordinate back into an address, which is what a click-anywhere or drag-a-pin interface needs, and the Geocoding API reference covers both directions along with the parameters that narrow results by country or type.
A found address is usually a starting point rather than a result. The Routing API takes the coordinates straight from a search result, which is the whole from-and-to interface in two calls.