A Responsive, CMS-driven, multi-pin Google Map

This fully-customizable, fully-responsive, CMS-driven Google Map works great for real estate projects, multi-location clients, point-of-interest maps, member community maps, & more.

View in Webflow
See it in action
674 Myrtle St NE
Atlanta, GA 30308
488 Flat Shoals Ave SE
Atlanta, GA 30316
1051 Ponce De Leon Ave NE
Atlanta, GA 30306
  •  
Get directions
264 Memorial Dr SE
Atlanta, GA 30312
736 Ponce De Leon Ave NE
Atlanta, GA 30306
968 Memorial Dr SE
Atlanta, GA 30316
437 Moreland Ave NE
Atlanta, GA 30307
1170 Howell Mill Rd
Atlanta, GA 30318
432 Moreland Ave NE
Atlanta, GA 30307
931 Monroe Dr NE
Atlanta, GA 30308
675 Ponce De Leon Ave NE N 219 Floor 2
Atlanta, GA 30308
  •  
Get directions
99 Krog St NE
Atlanta, GA 30307
644 North Highland Avenue Northeast #130
Atlanta, GA 30306
2928 E Ponce de Leon Ave
Decatur, GA 30030
2855 Piedmont Rd NE
Atlanta, GA 30305
714 Moreland Ave SE Suite D
Atlanta, GA 30316
Implementation notes

Update: 03/31/2023 - Updated focus states for accessibility.

1. Create a 🟨 Locations collection with all desired fields. Include Latitude & Longitude fields as plain text (not numbers).

2. Create a 🟨 Locations collection list on a static page. Apply the Location Item class to the collection items for later creating the locations array.

3. Create a hidden embed inside the collection item with any dynamic data you'd like to reference in the javascript. Latitude & Longitude coordinates are required for placing the location's pin & the slug for linking the collection to the pin's info window.

<div class="data---slug w-dyn-bind-empty">{{slug}}</div>
<div class="data---latitude w-dyn-bind-empty">{{latitude}}</div>
<div class="data---longitude w-dyn-bind-empty">{{longitude}}</div>

3.Create a hidden div inside the collection item named Data - Info Window & include all of the content you'd like in the map pin's info window.

4.Create an embed with the following javascript to open the pin's info window on click from the 🟨 Locations collection item. Then include & style any other data you'd like in the locations list.

<a href="javascript:google.maps.event.trigger(gmarkers['{{slug}}'],'click');" class="text-decoration---none"><div class="medium">{{name}}</div></a>
5. Include the Google Maps API script at the end of your page's body.
<script async defer src="https://maps.googleapis.com/maps/api/js?key[your-API-key]&callback=initMap" type="text/javascript"></script>
6. Include the map javascript between script tags after the Google Maps API script at the end of your page's body.
  // This script is adapted from Anna Sabatini's dynamic Google Maps project
  // https://discourse.webflow.com/t/tutorial-adding-several-markers-on-one-google-map-from-dynamic-collection/114410

	// Run code when page loads
  window.addEventListener('load', function () {

		// Create a locations array
    var locations = []

		// Add .location-wrapper class to the location Collection Item
    var dynPlaces = document.querySelectorAll('.w-dyn-item.location-item');   

  	// Define variables for the map info window
    dynPlaces.forEach( function(elem) {

			// Create places array
      var place = [];

  		// Define variables for each place
      var dataTitle = elem.querySelector('.data---slug').innerText; // Define slug for targeting the information window
      var dataLat = Number(elem.querySelector('.data---latitude').innerText); // Define latitude point for pin
      var dataLong = Number(elem.querySelector('.data---longitude').innerText); // Define longitude point for pin
      var infoWindowContent = elem.querySelector('.data---info-window').innerHTML; // Define content wrapper for the information window

      place.push(dataTitle, infoWindowContent, dataLat, dataLong); // Add variables to each place

      locations.push(place);   // Add each place to the locations array
    });

		// Map settings
    var map = new google.maps.Map(document.getElementById('map'), {
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      streetViewControl: false,
      mapTypeControl: false,
      fullscreenControl: false,
      scrollwheel: false,
      
      // Json map styling via https://mapstyle.withgoogle.com
      styles: [
        {
          "elementType": "geometry",
          "stylers": [
            {
              "color": "#f5f5f5"
            }
          ]
        },
        {
          "elementType": "labels.icon",
          "stylers": [
            {
              "visibility": "off"
            }
          ]
        },
        {
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#616161"
            }
          ]
        },
        {
          "elementType": "labels.text.stroke",
          "stylers": [
            {
              "color": "#f5f5f5"
            }
          ]
        },
        {
          "featureType": "administrative.land_parcel",
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#bdbdbd"
            }
          ]
        },
        {
          "featureType": "administrative.province",
          "elementType": "geometry.stroke",
          "stylers": [
            {
              "color": "#bababa"
            },
            {
              "visibility": "on"
            },
            {
              "weight": 1.5
            }
          ]
        },
        {
          "featureType": "poi",
          "stylers": [
            {
              "color": "#bababa"
            },
            {
              "visibility": "on"
            }
          ]
        },
        {
          "featureType": "poi",
          "elementType": "geometry.fill",
          "stylers": [
            {
              "color": "#eeeeee"
            }
          ]
        },
        {
          "featureType": "poi",
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#757575"
            }
          ]
        },
        {
          "featureType": "poi",
          "elementType": "labels.text.stroke",
          "stylers": [
            {
              "color": "#f5f5f5"
            }
          ]
        },
        {
          "featureType": "poi.park",
          "elementType": "geometry",
          "stylers": [
            {
              "color": "#e5e5e5"
            }
          ]
        },
        {
          "featureType": "poi.park",
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#9e9e9e"
            }
          ]
        },
        {
          "featureType": "road",
          "stylers": [
            {
              "visibility": "simplified"
            }
          ]
        },
        {
          "featureType": "road",
          "elementType": "geometry",
          "stylers": [
            {
              "color": "#ffffff"
            }
          ]
        },
        {
          "featureType": "road.arterial",
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#757575"
            }
          ]
        },
        {
          "featureType": "road.highway",
          "elementType": "geometry",
          "stylers": [
            {
              "color": "#dadada"
            }
          ]
        },
        {
          "featureType": "road.highway",
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#616161"
            }
          ]
        },
        {
          "featureType": "road.local",
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#9e9e9e"
            }
          ]
        },
        {
          "featureType": "transit.line",
          "elementType": "geometry",
          "stylers": [
            {
              "color": "#e5e5e5"
            }
          ]
        },
        {
          "featureType": "transit.station",
          "elementType": "geometry",
          "stylers": [
            {
              "color": "#eeeeee"
            }
          ]
        },
        {
          "featureType": "water",
          "elementType": "geometry",
          "stylers": [
            {
              "color": "#c9c9c9"
            }
          ]
        },
        {
          "featureType": "water",
          "elementType": "labels.text.fill",
          "stylers": [
            {
              "color": "#9e9e9e"
            }
          ]
        }
      ]
    });

    // Create info windows
    var infowindow = new google.maps.InfoWindow();

 		// Style markers (reference svgMarker as icon in createMarker function to use)
    /* 
    const svgMarker = {
      path: "M3.18236 3.94954C1.59126 5.64764 0.594653 8.12129 0.633351 10.448C0.71416 15.3102 2.90579 17.1508 6.41061 23.8426C7.67311 26.7873 8.99079 29.9032 10.244 35.0637C10.4182 35.8249 10.588 36.532 10.6666 36.5933C10.7451 36.6546 10.915 35.945 11.0892 35.1838C12.3424 30.0232 13.6601 26.9099 14.9226 23.9652C18.4274 17.2733 20.619 15.4327 20.6998 10.5705C20.7385 8.24379 19.7395 5.76766 18.1484 4.06956C16.3308 2.12977 13.5893 0.694173 10.6666 0.634142C7.74386 0.574072 4.99993 2.00974 3.18236 3.94954Z",
      fillColor: "#1169FE",
      fillOpacity: 1,
      strokeWeight: 1.26462,
      strokeColor: "#004FD6",
      rotation: 0,
      scale: 1,
      anchor: new google.maps.Point(15, 30),
    };
    */

		// Create markers
    function createMarker(latlng, html) {
      var marker = new google.maps.Marker({
        position: latlng,
        map: map,
        icon: "https://cdn.prod.website-files.com/631fe6ec99d4fc7b8a51759c/6324065e9ce860443217c6f7_Google_Maps_pin%201.svg"
      });

 		// Define info window for each marker
      google.maps.event.addListener(marker, 'click', function() {
        infowindow.setContent(html);
        infowindow.open(map, marker);
      });
      return marker;
    }

    gmarkers = [];
    for (var i = 0; i < locations.length; i++) {
      gmarkers[locations[i][0]] =
        createMarker(new google.maps.LatLng(locations[i][2], locations[i][3]), // passing lat and long
                                locations[i][1]); // passing Info-window information
    }
    
    // Create map bounds and center map
    var bounds = new google.maps.LatLngBounds();
    var northwest = new google.maps.LatLng(33.7859225, -84.4166867); // Northwest bound
    var southeast = new google.maps.LatLng(33.744205, -84.273109); // Southeast bound
    bounds.extend(northwest);
    bounds.extend(southeast);
    map.fitBounds(bounds);
    map.setCenter(bounds.getCenter());
    
  }, false);

6.Create a div with the ID #map for the map to appear in. Position it as needed.

7. Customize the map styling with Google's Styling Wizard. Replace the json in the styles section of the javascript.

8. Treat yourself to a night on the town. You are done.