DEV Community

Cover image for Add Address Autocomplete to a MapLibre GL Map (with Click-to-Address Reverse Geocoding)
Casey Rivers for Geoapify Maps API

Posted on

Add Address Autocomplete to a MapLibre GL Map (with Click-to-Address Reverse Geocoding)

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:

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

  1. Set Up a MapLibre GL Map
  2. Add the Geoapify Address Autocomplete Field
  3. Sync Autocomplete Selection with the Map
  4. Add Reverse Geocoding on Map Click
  5. Explore the Demo
  6. Summary
  7. 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>
Enter fullscreen mode Exit fullscreen mode

Create the map container

<div id="map"></div>
Enter fullscreen mode Exit fullscreen mode

Style it to fill the viewport:

html, body {
  margin: 0;
  height: 100%;
  width: 100%;
}

#map {
  height: 100%;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

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.

MapLibre GL map centered on Washington DC with navigation controls visible

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
.autocomplete-panel {
  position: absolute;
  top: 10px;
  left: 10px;
  width: 400px;
  z-index: 1002;
}
Enter fullscreen mode Exit fullscreen mode

Initialize the autocomplete widget

const autocompleteInput = new autocomplete.GeocoderAutocomplete(
  document.getElementById("autocomplete"),
  myAPIKey,
  { /* options */ }
);
Enter fullscreen mode Exit fullscreen mode

The GeocoderAutocomplete widget handles API calls and renders the dropdown automatically.

Address autocomplete dropdown showing suggestions over the map

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:

  1. Move the map to that location
  2. 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
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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.

Map with marker placed at selected address location after autocomplete selection

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);
  });
});
Enter fullscreen mode Exit fullscreen mode

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;
    });
}
Enter fullscreen mode Exit fullscreen mode

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.

User clicking on the map with the address appearing in the autocomplete field and a marker placed

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

  1. Type an address β†’ Select from dropdown β†’ Map flies to location with marker
  2. Click on the map β†’ Address appears in input field β†’ Marker placed at click point
  3. 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}`
};
Enter fullscreen mode Exit fullscreen mode

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:

  1. Address autocomplete - type to search, select to fly to location
  2. 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:


FAQ

Q: How do I restrict autocomplete results to a specific country?

A: Pass a filter option when initializing the autocomplete: { filter: { countrycode: "us" } }. See the filter documentation for more options.

Q: Can I use a different marker icon?

A: Yes. You can use any HTML element as a marker: an <img>, <div>, or inline SVG. The Marker Icon API offers customizable pins with different colors, shapes, and icons.

Q: How do I prevent marker clicks from triggering the map click handler?

A: Check if the click originated from a marker element:

map.on("click", (e) => {
  if (e.originalEvent.target.closest(".maplibregl-marker")) return;
  // ... your reverse geocoding logic
});
Enter fullscreen mode Exit fullscreen mode

Q: What happens if reverse geocoding returns no results?

A: This can happen for clicks in oceans or remote areas. Check for empty results and handle gracefully:

if (!result || !result.features || !result.features.length) {
  console.log("No address found at this location");
  return;
}
Enter fullscreen mode Exit fullscreen mode

Q: Can I use this with React or Vue?

A: Yes. The autocomplete library works with any framework. There's also a dedicated React package. For MapLibre, use the standard JS library or community wrappers like react-map-gl.

Q: How do I change the map style dynamically?

A: Use map.setStyle(newStyleUrl). Note that you may need to re-add event listeners after a style change. Use map.once("style.load", ...) to know when the new style is ready.

Q: What's the difference between forward and reverse geocoding?

A: Forward geocoding converts an address (text) to coordinates. Reverse geocoding converts coordinates to an address. In this tutorial, autocomplete uses forward geocoding, and map clicks use reverse geocoding.


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)