Web Components in the Maps JavaScript API (Preview)

Web Components are a popular W3C standard that encapsulate HTML, CSS, and JS in custom and reusable HTML elements. These reusable components can range from atomic pieces of functionality, like displaying the star rating for a place, to more complex business logic. This guide describes Web Components available in Maps JavaScript API.

For more information about the standard itself, see Web Components.

Audience

This documentation is designed to let you quickly start exploring and developing applications with Web Components. You should be familiar with HTML and CSS programming concepts.

Display a Map

The easiest way to start learning about Web Components is to see an example. The following example displays a map of the San Jose area.

TypeScript

// This example adds a map using web components.
async function initMap(): Promise<void> {
    const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
    console.log('Maps JavaScript API loaded.');
}

initMap();

JavaScript

// This example adds a map using web components.
async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");

  console.log("Maps JavaScript API loaded.");
}

initMap();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

gmp-map {
  height: 400px;
}

HTML

<html>
  <head>
    <title>Add a Map Web Component</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <gmp-map
      center="37.4220656,-122.0840897"
      zoom="10"
      map-id="DEMO_MAP_ID"
    ></gmp-map>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "beta"});</script>
  </body>
</html>

Try Sample

In this example there are a few things to note:

  1. The Maps JavaScript API is called asynchronously. The callback function is used to know when the API has loaded.
  2. Presentation of the map is defined with the <gmp-map> custom element.
  3. Map properties are defined by specifying attributes in the <gmp-map> custom element.
  4. Styling can be applied inline to custom elements or declared in a separate CSS file.

Style the basemap

A map ID is an identifier associated with a specific map style or feature. To take advantage of optional cloud configuration features, replace the cloud-based maps styling DEMO_MAP_ID with your own map ID. To learn how to create a map ID and configure a custom style, visit Cloud-based Maps Styling.

Add markers to the map

Just as one can nest built-in HTML tags to create complex content hierarchies, one can also nest <gmp-advanced-marker> inside an element to display one or more map markers.

TypeScript

// This example adds a map with markers, using web components.
async function initMap(): Promise<void> {
    const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
    const { AdvancedMarkerElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

    console.log('Maps JavaScript API loaded.');
}

initMap();

JavaScript

// This example adds a map with markers, using web components.
async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");

  console.log("Maps JavaScript API loaded.");
}

initMap();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

gmp-map {
  height: 400px;
}

HTML

<html>
  <head>
    <title>Add a Map with Markers using Web Components</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <gmp-map center="43.4142989,-124.2301242" zoom="4" map-id="DEMO_MAP_ID">
      <gmp-advanced-marker
        position="37.4220656,-122.0840897"
        title="Mountain View, CA"
      ></gmp-advanced-marker>
      <gmp-advanced-marker
        position="47.648994,-122.3503845"
        title="Seattle, WA"
      ></gmp-advanced-marker>
    </gmp-map>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "beta"});</script>
  </body>
</html>

Try Sample

Here we've added two <gmp-advanced-marker> elements inside the <gmp-map> custom element. Text for title provides an additional hover text and accessibility label for the specified element.

JavaScript Events

A major benefit of Web Components is ease of use. With a few lines of code, one can display a Map with limited knowledge of JavaScript or advanced programming. Once implemented, the code follows the familiar patterns of other HTML elements. For example, one can use the native browser eventing system to react to Map or Advanced Marker actions, such as a marker click.

In your HTML, set the gmp-clickable attribute on the gmp-advanced-marker element to make a marker clickable. Use advancedMarker.addEventListener to handle click events.

TypeScript

// This example adds a map using web components.
async function initMap(): Promise<void> {
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

  console.log('Maps JavaScript API loaded.');

  const advancedMarkers = document.querySelectorAll("#marker-click-event-example gmp-advanced-marker");

  for (const advancedMarker of advancedMarkers) {

    customElements.whenDefined(advancedMarker.localName).then(async () => {
      advancedMarker.addEventListener('gmp-click', async () => {

        const infoWindow = new google.maps.InfoWindow({
          //@ts-ignore
          content: advancedMarker.title,
        });
        infoWindow.open({
          //@ts-ignore
          anchor: advancedMarker
        });
      });
    });
  }
}

initMap();

JavaScript

// This example adds a map using web components.
async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");

  console.log("Maps JavaScript API loaded.");

  const advancedMarkers = document.querySelectorAll(
    "#marker-click-event-example gmp-advanced-marker",
  );

  for (const advancedMarker of advancedMarkers) {
    customElements.whenDefined(advancedMarker.localName).then(async () => {
      advancedMarker.addEventListener("gmp-click", async () => {
        const infoWindow = new google.maps.InfoWindow({
          //@ts-ignore
          content: advancedMarker.title,
        });

        infoWindow.open({
          //@ts-ignore
          anchor: advancedMarker,
        });
      });
    });
  }
}

initMap();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

gmp-map {
  height: 400px;
}

HTML

<html>
  <head>
    <title>Add a Map Web Component with Events</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <gmp-map
      id="marker-click-event-example"
      center="43.4142989,-124.2301242"
      zoom="4"
      map-id="DEMO_MAP_ID"
    >
      <gmp-advanced-marker
        position="37.4220656,-122.0840897"
        title="Mountain View, CA"
        gmp-clickable
      ></gmp-advanced-marker>
      <gmp-advanced-marker
        position="47.648994,-122.3503845"
        title="Seattle, WA"
        gmp-clickable
      ></gmp-advanced-marker>
    </gmp-map>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "beta"});</script>
  </body>
</html>

Try Sample

In this example, initMap represents the required callback function once the Maps JavaScript API loads completely. The code establishes listeners to each marker and presents an info window when each marker is clicked.

What's next