MapSnippets logoMapSnippets logo

Store Locator with MapLibre GL JS

MapLibre GL JS

Build a store locator with a sidebar list and interactive map markers using MapLibre GL JS.

progress_activityLoading map...
const stores = [
  { name: 'Store Marais', address: '15 Rue des Francs Bourgeois', lng: 2.3621, lat: 48.8571 },
  { name: 'Store Louvre', address: '2 Rue de Rivoli', lng: 2.3376, lat: 48.8606 },
  { name: 'Store Montmartre', address: '30 Rue Lepic', lng: 2.3334, lat: 48.8847 },
  { name: 'Store Latin Quarter', address: '10 Rue Mouffetard', lng: 2.3499, lat: 48.8430 },
  { name: 'Store Bastille', address: '5 Rue de la Roquette', lng: 2.3715, lat: 48.8534 }
];
const map = new maplibregl.Map({
  container: 'map',
  style: 'https://api.maptiler.com/maps/streets-v4/style.json?key=YOUR_MAPTILER_KEY',
  center: [2.3500, 48.8600],
  zoom: 13
});
const panel = document.getElementById('store-panel');
stores.forEach(s => {
  const popup = new maplibregl.Popup({ offset: 25 }).setHTML(`<strong>${s.name}</strong><br>${s.address}`);
  const marker = new maplibregl.Marker({ color: '#2196F3' })
    .setLngLat([s.lng, s.lat])
    .setPopup(popup)
    .addTo(map);
  const item = document.createElement('div');
  item.className = 'store-item';
  item.innerHTML = `<strong>${s.name}</strong>${s.address}`;
  item.addEventListener('click', () => {
    map.flyTo({ center: [s.lng, s.lat], zoom: 16 });
    marker.togglePopup();
  });
  panel.appendChild(item);
});

How it works

The store locator pairs a sidebar list with map markers. Each store in the data array gets a maplibregl.Marker on the map and a clickable entry in the sidebar panel. Clicking a sidebar item flies the map to that store and toggles its popup.

The sidebar is absolutely positioned over the left edge of the viewport. The #map element has a left margin matching the sidebar width so the two never overlap. Markers and list items are created in the same loop to keep data in sync.

The flyTo method provides a smooth animated transition to the selected store. The popup opens automatically via togglePopup() after the camera moves.

Key APIs

API Description Docs
maplibregl.Marker Place store markers on the map maplibre.org docs
map.flyTo() Animated camera transition to a store maplibre.org docs
maplibregl.Popup Show store details on click maplibre.org docs

FAQ

How do I add search/filter to the store list?

Add a text input above the store list and filter the DOM elements on keyup by matching against the store name or address.

How do I load store data from an API?

Replace the stores array with a fetch() call to your API endpoint, then build markers and list items from the response data.

Can I highlight the active store in the sidebar?

Add an active CSS class to the clicked item and remove it from all others. Use the class to change background or border color.

Common mistakes

  • Forgetting to set margin-left on the map container: the map renders underneath the sidebar
  • Using [lat, lng] instead of [lng, lat]: MapLibre uses GeoJSON coordinate order
  • Not calling map.resize() if the sidebar is toggled dynamically: MapLibre caches the container size
auto_awesome

Build maps using MapLibre GL JS with AI

Generate code like this store locator with maplibre gl js example using the MapLibre GL JS skill in your IDE.