Building a location picker often means giving users two ways to select an address: typing it or clicking on the map. In this tutorial, we'll combine both approaches using MapLibre GL and Geoapify to create a smooth "search or click" UX.
Try the live demo:
β‘οΈ View on CodePen
APIs used:
- Address Autocomplete API - real-time suggestions as users type
- Reverse Geocoding API - convert map clicks to addresses
- Map Tiles - vector map styles for MapLibre GL
- Map Marker Icon API - custom marker icons
What you'll build:
- A MapLibre GL map with Geoapify vector tiles
- An address autocomplete field that flies to the selected location
- Click-to-address functionality using reverse geocoding
- A reusable marker that updates for both interactions
π§ Table of Contents
- Set Up a MapLibre GL Map
- Add the Geoapify Address Autocomplete Field
- Sync Autocomplete Selection with the Map
- Add Reverse Geocoding on Map Click
- Explore the Demo
- Summary
- FAQ
Step 1: Set Up a MapLibre GL Map
Start by loading MapLibre GL JS and initializing a map with Geoapify vector tiles.
Include MapLibre GL
Add the CSS and JavaScript from a CDN:
<!-- MapLibre GL CSS -->
<link href="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css" rel="stylesheet" />
<!-- MapLibre GL JS -->
<script src="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js"></script>
Create the map container
<div id="map"></div>
Style it to fill the viewport:
html, body {
margin: 0;
height: 100%;
width: 100%;
}
#map {
height: 100%;
width: 100%;
}
Initialize the map
Create a new MapLibre map using a Geoapify style.json URL:
const myAPIKey = "YOUR_API_KEY";
const map = new maplibregl.Map({
container: "map",
style: `https://maps.geoapify.com/v1/styles/osm-bright-grey/style.json?apiKey=${myAPIKey}`,
center: [-77.0234, 38.9088], // Washington DC
zoom: 12,
maxZoom: 20
});
// Add navigation controls
map.addControl(new maplibregl.NavigationControl());
The style URL points to Geoapify's vector map tiles. You can choose from different styles like osm-bright, dark-matter, positron, and others. See the Map Tiles documentation for the full list.
π API Key: Sign up at geoapify.com to get a free API key.
A MapLibre GL map initialized with Geoapify vector tiles.
Step 2: Add the Geoapify Address Autocomplete Field
Next, we'll add an address search field that suggests locations as the user types.
Include the Geocoder Autocomplete library
<!-- Geoapify Geocoder Autocomplete CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@geoapify/geocoder-autocomplete@3.0.1/styles/minimal.css" />
<!-- Geoapify Geocoder Autocomplete JS -->
<script src="https://cdn.jsdelivr.net/npm/@geoapify/geocoder-autocomplete@3.0.1/dist/index.min.js"></script>
The library comes with several built-in themes: minimal, minimal-dark, round-borders, and round-borders-dark.
Create the autocomplete container
Position the autocomplete field over the map:
<div class="autocomplete-panel">
<div id="autocomplete" class="autocomplete-container"></div>
</div>
.autocomplete-panel {
position: absolute;
top: 10px;
left: 10px;
width: 400px;
z-index: 1002;
}
Initialize the autocomplete widget
const autocompleteInput = new autocomplete.GeocoderAutocomplete(
document.getElementById("autocomplete"),
myAPIKey,
{ /* options */ }
);
The GeocoderAutocomplete widget handles API calls and renders the dropdown automatically.
The autocomplete dropdown appears as the user types, showing matching address suggestions.
Step 3: Sync Autocomplete Selection with the Map
When the user selects an address, we want to:
- Move the map to that location
- Place a marker at the coordinates
Listen to the select event
let marker;
autocompleteInput.on("select", (location) => {
// Remove existing marker
if (marker) {
marker.remove();
}
if (location) {
// Create a new marker at the selected location
marker = new maplibregl.Marker({
element: createMarkerIcon(),
offset: [0, -25]
})
.setLngLat([location.properties.lon, location.properties.lat])
.addTo(map);
// Fly to the selected location
map.flyTo({
center: [location.properties.lon, location.properties.lat],
zoom: 14
});
}
});
The location.properties object contains the coordinates (lon, lat) and the formatted address.
Create a custom marker icon
Use the Geoapify Map Marker Icon API to generate a custom pin:
function createMarkerIcon() {
const img = document.createElement("img");
img.src = `https://api.geoapify.com/v2/icon/?type=awesome&color=%23ff5b5f&size=50&scaleFactor=2&apiKey=${myAPIKey}`;
img.style.width = "38px";
img.style.height = "55px";
return img;
}
The scaleFactor=2 renders the icon at double resolution for sharp display on retina screens.
π‘ Marker offset: The
offset: [0, -25]shifts the marker so that the pin's tip (not its center) aligns with the coordinates. The offset is calculated as-(icon height - shadow offset) / 2.
After selecting an address, the map flies to the location and displays a marker.
Step 4: Add Reverse Geocoding on Map Click
Now let's add the second interaction: clicking on the map to get the address at that point. This uses the Geoapify Reverse Geocoding API.
Listen to map clicks
map.on("click", function (e) {
const lat = e.lngLat.lat;
const lon = e.lngLat.lng;
// Call reverse geocoding for the clicked location
getAddressByLatLon(lat, lon).then((location) => {
if (marker) {
marker.remove();
}
// Set the address in the autocomplete input
autocompleteInput.setValue(location.properties.formatted);
// Place a marker at the returned coordinates
marker = new maplibregl.Marker({
element: createMarkerIcon(),
offset: [0, -25]
})
.setLngLat([location.properties.lon, location.properties.lat])
.addTo(map);
});
});
Implement the reverse geocoding function
function getAddressByLatLon(lat, lon) {
return fetch(
`https://api.geoapify.com/v1/geocode/reverse?lat=${lat}&lon=${lon}&apiKey=${myAPIKey}`
)
.then((result) => result.json())
.then((result) => {
if (result && result.features && result.features.length) {
return result.features[0];
}
return null;
});
}
The Reverse Geocoding API takes latitude and longitude coordinates and returns the nearest address. The response includes properties.formatted (the full address string) and individual components like street, city, and country.
π Learn more: See the full API reference in the Reverse Geocoding documentation.
Clicking anywhere on the map triggers reverse geocoding. The address fills the input field and a marker appears.
Step 5: Explore the Demo
The live CodePen demo shows both interactions working together.
Try these flows
- Type an address β Select from dropdown β Map flies to location with marker
- Click on the map β Address appears in input field β Marker placed at click point
- Switch between both β Notice how one marker and one input are reused
Theme switcher
The demo includes a theme selector that switches both the autocomplete style and the map tiles between light and dark modes:
const mapStyles = {
light: `https://maps.geoapify.com/v1/styles/osm-bright-grey/style.json?apiKey=${myAPIKey}`,
dark: `https://maps.geoapify.com/v1/styles/dark-matter-brown/style.json?apiKey=${myAPIKey}`
};
Where to use this pattern
This "search or click" UX works well for:
- Delivery forms - let users type their address or drop a pin on their exact location
- Location pickers - allow users to choose meeting points or drop-off locations
- Real estate apps - search for properties or explore by clicking on the map
- Onboarding flows - capture user location during account setup
π Try it in the interactive demo:
Summary
You've built a location picker with two interaction methods:
- Address autocomplete - type to search, select to fly to location
- Reverse geocoding - click the map to get the address at that point
Both interactions share a single marker and input field, creating a consistent, intuitive UX.
Useful links:
- Geocoder Autocomplete on npm
- Address Autocomplete API docs
- Reverse Geocoding API docs
- Map Tiles docs
- Map Marker Icon API docs
FAQ
Q: How do I restrict autocomplete results to a specific country?
A: Use the filter option with countrycode, rect (bounding box), or circle parameters. For example: filter: { countrycode: ["us", "ca"] } limits results to USA and Canada. See the Address Autocomplete API docs.
Q: What data does the Reverse Geocoding API return?
A: The API returns a complete address with components like street, housenumber, city, postcode, country, plus formatted display address, coordinates, timezone information, and confidence scores. See the Reverse Geocoding API docs.
Q: Can I use the autocomplete with React or Angular?
A: Yes. We provide dedicated wrapper libraries for popular frameworks:
Q: What map styles are available?
A: Geoapify offers multiple vector map styles including osm-bright, osm-bright-grey, dark-matter, dark-matter-brown, positron, and more. See the Map Tiles docs for the full list.
Q: Can I customize marker icons?
A: Yes. The Marker Icon API lets you generate custom pins with different colors, sizes, icon types (awesome, material), shadows, and scale factors for retina displays.
Q: How can I experiment with these APIs before coding?
A: Use our interactive playgrounds to test API parameters and generate code:
- Map Tiles Playground - try different map styles
- Marker Icon Playground - design custom markers
- Autocomplete Playground - test address search
- Reverse Geocoding Playground - test coordinate-to-address
Try It Now
π Open the Live Demo
Sign up at geoapify.com and get your free API key to start building interactive location pickers.




Top comments (0)