Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
mapbox avatar

Mapbox Store Locator Patterns

  • 1.1k installs
  • 71 repo stars
  • Updated August 4, 2026
  • mapbox/mapbox-agent-skills

mapbox-store-locator-patterns is a Mapbox agent skill that implements reliable, performant store locators and location-based interfaces for developers building map-driven finder experiences.

About

mapbox-store-locator-patterns is an official Mapbox agent skill from mapbox/mapbox-agent-skills that documents architecture for store locators and location finders. The readme defines six core components: a map with markers, GeoJSON location data, an interactive list, search and filter controls, user location with distance calculation, and optional directions. It includes a GeoJSON FeatureCollection example with Point geometry, store properties such as name, address, phone, category, and hours, plus guidance on wiring list-map interaction. Developers reach for mapbox-store-locator-patterns when shipping retail or service locator pages that must stay performant with real coordinates, filtering, and distance-aware UX on Mapbox.

  • Ready-to-use architecture for maps with markers, GeoJSON data, interactive lists, search, and directions
  • Scalable marker strategies: HTML Markers for <100 locations, Symbol Layers for 100-1000, Clustering for >1000
  • Complete GeoJSON data structure with properties for name, address, category, hours and phone
  • Copy-paste JavaScript patterns for HTML markers with popups and Symbol Layer implementations
  • Optimized patterns that prevent common performance pitfalls when displaying hundreds of store locations

Mapbox Store Locator Patterns by the numbers

  • 1,142 all-time installs (skills.sh)
  • +40 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #342 of 2,245 Frontend Development skills by installs in the Skillselion catalog
  • Security screen: MEDIUM risk (skills.sh audit)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mapbox/mapbox-agent-skills --skill mapbox-store-locator-patterns

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1.1k
repo stars71
Security audit3 / 3 scanners passed
Last updatedAugust 4, 2026
Repositorymapbox/mapbox-agent-skills

How do you build a Mapbox store locator app?

Quickly implement reliable, performant store locators and location-based interfaces using Mapbox.

Who is it for?

Frontend developers implementing retail or service store finders with Mapbox maps, GeoJSON data, and interactive location search.

Skip if: Projects without location data, non-map UIs, or teams that only need server-side geocoding without a locator frontend.

When should I use this skill?

The user asks to build a store locator, location finder, Mapbox marker map, or GeoJSON-driven search and filter UI.

What you get

GeoJSON store datasets, Mapbox maps with markers, searchable store lists, and distance-aware locator UI patterns.

  • GeoJSON store dataset
  • Interactive locator UI
  • Map marker and search components

By the numbers

  • Documents 6 core store locator architecture components
  • Uses GeoJSON FeatureCollection with Point geometry for store data

Files

SKILL.mdMarkdownGitHub ↗

Store Locator Patterns Skill

Comprehensive patterns for building store locators, restaurant finders, and location-based search applications with Mapbox GL JS. Covers marker display, filtering, distance calculation, interactive lists, and directions integration.

When to Use This Skill

Use this skill when building applications that:

  • Display multiple locations on a map (stores, restaurants, offices, etc.)
  • Allow users to filter or search locations
  • Calculate distances from user location
  • Provide interactive lists synced with map markers
  • Show location details in popups or side panels
  • Integrate directions to selected locations

Dependencies

Required:

  • Mapbox GL JS v3.x
  • @turf/turf - For spatial calculations (distance, area, etc.)

Installation:

npm install mapbox-gl @turf/turf

Core Architecture

Pattern Overview

A typical store locator consists of:

1. Map Display - Shows all locations as markers 2. Location Data - GeoJSON with store/location information 3. Interactive List - Side panel listing all locations 4. Filtering - Search, category filters, distance filters 5. Detail View - Popup or panel with location details 6. User Location - Geolocation for distance calculation. For the blue dot location indicator, use the built-in mapboxgl.GeolocateControl — simpler than custom markers. 7. Directions - Route to selected location (optional)

Data Structure

GeoJSON format for locations:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [-77.034084, 38.909671]
      },
      "properties": {
        "id": "store-001",
        "name": "Downtown Store",
        "address": "123 Main St, Washington, DC 20001",
        "phone": "(202) 555-0123",
        "hours": "Mon-Sat: 9am-9pm, Sun: 10am-6pm",
        "category": "retail",
        "website": "https://example.com/downtown"
      }
    }
  ]
}

Key properties:

  • id - Unique identifier for each location
  • name - Display name
  • address - Full address for display and geocoding
  • coordinates - [longitude, latitude] format
  • category - For filtering (retail, restaurant, office, etc.)
  • Custom properties as needed (hours, phone, website, etc.)

Basic Store Locator Implementation

Step 1: Initialize Map and Data

import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';

// Store locations data
const stores = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [-77.034084, 38.909671]
      },
      properties: {
        id: 'store-001',
        name: 'Downtown Store',
        address: '123 Main St, Washington, DC 20001',
        phone: '(202) 555-0123',
        category: 'retail'
      }
    }
    // ... more stores
  ]
};

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/standard',
  center: [-77.034084, 38.909671],
  zoom: 11
});

Step 2: Add Markers to Map

Marker strategy by location count:

CountStrategyReason
Fewer than 100HTML MarkersFull DOM/CSS control; DOM node count is manageable
100–1,000Symbol Layer (default)Renders on the GPU via WebGL — one <canvas>, zero per-point DOM elements
More than 1,000ClusteringReduces visual clutter at large scale
HTML Markers create one DOM element per point. Beyond ~100 locations the browser spends too much time on layout/paint. Symbol layers bypass the DOM entirely — the GPU draws all points in a single WebGL draw call.

Symbol Layer implementation (best for 100–1,000 locations). For HTML Markers (fewer than 100) or Clustering (more than 1,000), see references/markers.md.

map.on('load', () => {
  // Add store data as source
  map.addSource('stores', {
    type: 'geojson',
    data: stores
  });

  // Add custom marker image
  map.loadImage('/marker-icon.png', (error, image) => {
    if (error) throw error;
    map.addImage('custom-marker', image);

    // Add symbol layer
    map.addLayer({
      id: 'stores-layer',
      type: 'symbol',
      source: 'stores',
      layout: {
        'icon-image': 'custom-marker',
        'icon-size': 0.8,
        'icon-allow-overlap': true,
        'text-field': ['get', 'name'],
        'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
        'text-offset': [0, 1.5],
        'text-anchor': 'top',
        'text-size': 12
      }
    });
  });

  // Handle marker clicks using Interactions API (recommended)
  map.addInteraction('store-click', {
    type: 'click',
    target: { layerId: 'stores-layer' },
    handler: (e) => {
      const store = e.feature;
      flyToStore(store);
      createPopup(store);
    }
  });

  // Or using traditional event listener:
  // map.on('click', 'stores-layer', (e) => {
  //   const store = e.features[0];
  //   flyToStore(store);
  //   createPopup(store);
  // });

  // Change cursor on hover
  map.on('mouseenter', 'stores-layer', () => {
    map.getCanvas().style.cursor = 'pointer';
  });

  map.on('mouseleave', 'stores-layer', () => {
    map.getCanvas().style.cursor = '';
  });
});

Step 3: Build Interactive Location List

function buildLocationList(stores) {
  const listingContainer = document.getElementById('listings');

  stores.features.forEach((store, index) => {
    const listing = listingContainer.appendChild(document.createElement('div'));
    listing.id = `listing-${store.properties.id}`;
    listing.className = 'listing';

    const link = listing.appendChild(document.createElement('a'));
    link.href = '#';
    link.className = 'title';
    link.id = `link-${store.properties.id}`;
    link.innerHTML = store.properties.name;

    const details = listing.appendChild(document.createElement('div'));
    details.innerHTML = `
      <p>${store.properties.address}</p>
      <p>${store.properties.phone || ''}</p>
    `;

    // Handle listing click
    link.addEventListener('click', (e) => {
      e.preventDefault();
      flyToStore(store);
      createPopup(store);
      highlightListing(store.properties.id);
    });
  });
}

function flyToStore(store) {
  map.flyTo({
    center: store.geometry.coordinates,
    zoom: 15,
    duration: 1000
  });
}

function createPopup(store) {
  const popups = document.getElementsByClassName('mapboxgl-popup');
  // Remove existing popups
  if (popups[0]) popups[0].remove();

  new mapboxgl.Popup({ closeOnClick: true })
    .setLngLat(store.geometry.coordinates)
    .setHTML(
      `<h3>${store.properties.name}</h3>
       <p>${store.properties.address}</p>
       <p>${store.properties.phone}</p>
       ${store.properties.website ? `<a href="${store.properties.website}" target="_blank">Visit Website</a>` : ''}`
    )
    .addTo(map);
}

// IMPORTANT: highlightListing MUST include scrollIntoView — without it,
// selecting a marker on the map won't scroll the sidebar to the listing.
function highlightListing(id) {
  // Remove existing highlights
  const activeItem = document.getElementsByClassName('active');
  if (activeItem[0]) {
    activeItem[0].classList.remove('active');
  }

  // Add highlight to selected listing
  const listing = document.getElementById(`listing-${id}`);
  listing.classList.add('active');

  // Scroll the selected listing into view (critical UX requirement)
  listing.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}

// Build the list on load
map.on('load', () => {
  buildLocationList(stores);
});

Reference Files

Load these references for additional patterns as needed:

ReferenceFileContents
HTML Markers & Clusteringreferences/markers.mdHTML Markers (< 100 locations), Clustering (> 1000 locations)
Search & Filterreferences/search-filter.mdText search, category filter
Geolocation & Directionsreferences/geolocation-directions.mdUser location, distance calculation, route directions
Styling & Layoutreferences/styling-layout.mdFull HTML/CSS layout, custom marker CSS
Performance & A11yreferences/optimization-a11y.mdDebounced search, data management, error handling, accessibility
Variations & Reactreferences/variations-react.mdMobile-first, fullscreen, map-only, React implementation

Resources

Related skills

How it compares

Choose mapbox-store-locator-patterns for end-to-end locator UI architecture instead of generic map styling or backend-only geocoding skills.

FAQ

What components does a Mapbox store locator need?

mapbox-store-locator-patterns lists six core pieces: a marker map, GeoJSON location data, an interactive list, search and filter, user location with distance, and optional directions integration.

What GeoJSON structure does mapbox-store-locator-patterns use?

mapbox-store-locator-patterns uses a FeatureCollection of Point features with properties like id, name, address, phone, category, and hours, following standard GeoJSON coordinate ordering.

Is Mapbox Store Locator Patterns safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

Frontend Developmentfrontendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.