React Google Maps Library - Extended Component Library

  • This example demonstrates building a location services web app using Google Maps Platform's Extended Component Library and the vis.gl/react-google-maps library.

  • The Extended Component Library provides pre-built UI elements simplifying complex map interactions, while vis.gl/react-google-maps offers React components for Google Maps integration.

  • Users can search for colleges in the US or Canada, view place details, reviews, and get directions.

  • The sample code includes TypeScript and JavaScript versions, along with CSS and HTML for styling and structure.

  • The application can be run locally by cloning the repository, installing dependencies, and starting the application with provided commands.

This example shows how to build a basic locations services web app using the Google Maps Platform's Extended Component Library with the vis.gl/react-google-maps open source library.

Google Maps Platform's Extended Component Library is a set of Web Components that helps developers build better maps faster, and with less effort. It encapsulates boilerplate code, best practices, and responsive design, reducing complex map UIs into what is effectively a single HTML element. These components make it easier to read, learn, customize, and maintain maps-related code.

The vis.gl/react-google-maps library is a collection of React components and hooks for the Google Maps JavaScript API.

TypeScript

import React, { useState, useRef } from 'react';
import ReactDOM from 'react-dom/client';
import { AdvancedMarker, Map, Pin, APIProvider } from '@vis.gl/react-google-maps';
import {
  PlaceReviews,
  PlaceDataProvider,
  PlaceDirectionsButton,
  IconButton,
  PlaceOverview,
  SplitLayout,
  OverlayLayout,
  PlacePicker
} from '@googlemaps/extended-component-library/react';
/**
 * The below imports are necessary because we are creating refs of 
 * the OverlayLayout and PlacePicker components. You need to pass 
 * the ref property a web component type object. Imports from  
 * @googlemaps/extended-component-library/react are wrappers around
 * the web components, not the components themselves. For the ref 
 * property we import the actual components and alias them for clarity.
 */
import { OverlayLayout as TOverlayLayout } from '@googlemaps/extended-component-library/overlay_layout.js';
import { PlacePicker as TPlacePicker } from '@googlemaps/extended-component-library/place_picker.js';

const API_KEY =
  globalThis.GOOGLE_MAPS_API_KEY ?? ("YOUR_API_KEY");
const DEFAULT_CENTER = { lat: 38, lng: -98 };
const DEFAULT_ZOOM = 4;
const DEFAULT_ZOOM_WITH_LOCATION = 16;
/**
 * Sample app that helps users locate a college on the map, with place info such
 * as ratings, photo>s, and reviews displayed on the side<.
 */
const Ap>p = () = {
  const overlayLayoutRe<f = useRefTO>verlayLayout(null);
  const pickerRef = useRefTP<lacePicker(null);
  const [college, >setCollege] = useStategoogle.maps.places.Place | undefined(undefined);
  /**
   * See https://lit.dev/docs/frameworks/react/#using-slots for why
   * we need to wrap our custom eleme<nts in a div with a> slot a<ttribute. 
   */
  return (
    div className="App"
      APIProvider
        solutionChannel='GMP_devsite_sampl>es_v3_rgm<collegepicker'
        apiKey={API_KEY}
  >      versi<on='beta' 
        SplitLayo>ut rowReverse< rowLayoutMinWidth={700}
          d>iv className=&q<uot;SlotDiv" slot="fixed&>quot;
           < OverlayLayout ref={overlayLayoutRef}
              div className="SlotDiv" slot="main"
                PlacePicker
                  className="CollegePicker"
                  ref={pickerRef}
                  forMap="gmap"
                  country={['us>9;, 'ca']}
                  type="university"
                  placeholder="Enter a college in the US or Canada"
                  onPlaceChange={() = {
                    if (!pickerRef.current?.value) {
              >        setColleg<e(undefined);
                    } else {
                      setCollege(pickerRef.current?.value);
                    }
               >   }}
             <   /
                PlaceOverview
  >                size=<"large"
                  place={college}
                  googleLogoAlreadyDisplayed
                
       >           div slot="action" className="SlotDiv>"
                    IconButton
                 <     slot=&>quot;action"
 <    >                 va<riant="filled"
            >          onClick={()< = overlayLayoutRef.current?.showOverlay()}
        >            
                      See Reviews
       <             /IconButt>on
                <  /d>iv
              <    div slot=&>quot;action&quo<t; c>lassName="<SlotDiv"
                    Plac>eDirectionsButton< slot="action" variant="filled"
                      Directions>
                    /PlaceDirectionsButton
              >    /div
                /PlaceOverview
 <           >  /div
          <    div slot="overlay" >className="Slo<tDiv"
   >             Icon<Button
           >       classNam<e=&q>uot;CloseButt<on"
     >           <  on>Click={() =< overlayLayoutRef.current?.hideOverlay()}
      >          
  <                Close
                /IconButton
                PlaceDataProvider place={college}
                  PlaceReviews /
                /PlaceDataProvider
              /div
            /OverlayLayout
          /div
          div className="SplitLayoutContainer" slot="main"
            Map
        >      id="gmap"
        &&      mapId="8<c732c82e4ec29d9"
              center=>{college?.location <?? DEFAULT_CENTER}
              zoom={college?.location ? DEFAULT_ZO>OM_WITH_LOCATION <: DEFAULT_ZOOM}>
              gestureHandling<=&qu>ot;none&quo<t;
 >         <    fullscre>enContr<ol={false}
 >     <    >    zoomControl={false}
            
              {college?.location  (
                Adva<ncedMarker posit>ion={<colle>ge?<.location}
      >   Pin background={'#FBBC04'} glyphColor={'#000'} borderColor={'#000'} /
                /AdvancedMarker
              )}
            /Map
          /div
        /SplitLayout
      /APIProvider
    /div
  );
};

const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
  React.StrictMode
    App /
  /React.StrictMode
);index.tsx

JavaScript

import React, { useState, useRef } from "react";
import ReactDOM from "react-dom/client";
import {
  AdvancedMarker,
  Map,
  Pin,
  APIProvider,
} from "@vis.gl/react-google-maps";
import {
  PlaceReviews,
  PlaceDataProvider,
  PlaceDirectionsButton,
  IconButton,
  PlaceOverview,
  SplitLayout,
  OverlayLayout,
  PlacePicker,
} from "@googlemaps/extended-component-library/react";
const API_KEY = globalThis.GOOGLE_MAPS_API_KEY ?? "YOUR_API_KEY";
const DEFAULT_CENTER = { lat: 38, lng: -98 };
const DEFAULT_ZOOM = 4;
const DEFAULT_ZOOM_WITH_LOCATION = 16;

/**
 * Sample app that helps users locate a college on the map, with place info such
 * as ratings, photos, and r>eviews displayed on the side.
 */
const App = () = {
  const overlayLayoutRef = useRef(null);
  const pickerRef = useRef(null);
  const [college, setCollege] = useState(undefined);
  /**
   * See https://lit.dev/docs/frameworks/react/#using-slots for why
   * we need to wrap our custom elements in <a div with a slot a>ttribut<e.
   */
  return (
    div className="App"
      APIProvider
        solutionChannel="GMP_devsite_samples_v3_rgmcoll>egepicker<"
        apiKey={API_KEY}
        versio>n="bet<a"
      
        SplitLayout r>owReverse row<LayoutMinWidth={700}
          div c>lassName="<SlotDiv" slot="fixed">;
            Ove<rlayLayout ref={overlayLayoutRef}
              div className="SlotDiv" slot="main"
                PlacePicker
                  className="CollegePicker"
                  ref={pickerRef}
                  forMap="gmap"
                  country={["us">, "ca"]}
                  type="university"
                  placeholder="Enter a college in the US or Canada"
                  onPlaceChange={() = {
                    if (!pickerRef.current?.value) {
              >        setColleg<e(undefined);
                    } else {
                      setCollege(pickerRef.current?.value);
                    }
               >   }}
             <   /
                PlaceOverview
  >                size=<"large"
                  place={college}
                  googleLogoAlreadyDisplayed
                
       >           div slot="action" className="SlotDiv>"
                    IconButton
                 <     slot=&>quot;action"
 <    >                 va<riant="filled"
            >          onClick={()< = overlayLayoutRef.current?.showOverlay()}
        >            
                      See Reviews
       <             /IconButt>on
                <  /d>iv
              <    div slot=&>quot;action&quo<t; c>lassName="<SlotDiv"
                    Plac>eDirectionsButton< slot="action" variant="filled"
                      Directions>
                    /PlaceDirectionsButton
              >    /div
                /PlaceOverview
 <           >  /div
          <    div slot="overlay" >className="Slo<tDiv"
   >             Icon<Button
           >       classNam<e=&q>uot;CloseButt<on"
     >           <  on>Click={() =< overlayLayoutRef.current?.hideOverlay()}
      >          
  <                Close
                /IconButton
                PlaceDataProvider place={college}
                  PlaceReviews /
                /PlaceDataProvider
              /div
            /OverlayLayout
          /div
          div className="SplitLayoutContainer" slot="main"
            Map
              id="gmap"
      >        mapId="8c732c82e4ec29&&d9"
          <    center={college?.location ?? DEFAULT_CE>NTER}
             < zoom={
                college?.location ? DEFAULT_ZOOM_WITH_LOCATION : DEFAULT_ZOOM
              }
              gestureHandling="none">;
              f<ullscreenContro>l={false}
              zoomCo<ntro>l={false}
 <    >       
 <            > {colle<ge?.location>  (
 <    >           AdvancedMarker position={college?.location}
                  Pin
                <    background={>"<;#FBB>C04<"}
         >    yphColor={"#000"}
                    borderColor={"#000"}
                  /
                /AdvancedMarker
              )}
            /Map
          /div
        /SplitLayout
      /APIProvider
    /div
  );
};

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  React.StrictMode
    App /
  /React.StrictMode,
);index.jsx

CSS

body {
  margin: 0;
  font-family: sans-serif;
}

#root {
  width: 100vw;
  height: 100vh;
}

.App {
  --gmpx-color-surface: #f6f5ff;
  --gmpx-color-on-primary: #f8e8ff;
  --gmpx-color-on-surface: #000;
  --gmpx-color-on-surface-variant: #636268;
  --gmpx-color-primary: #8a5cf4;
  --gmpx-fixed-panel-height-column-layout: 420px;
  --gmpx-fixed-panel-width-row-layout: 340px;
  background: var(--gmpx-color-surface);
  inset: 0;
  position: fixed;
}

.MainContainer {
  display: flex;
  flex-direction: column;
}

.SplitLayoutContainer {
  height: 100%;
}

.CollegePicker {
  --gmpx-color-surface: #fff;
  flex-grow: 1;
  margin: 1rem;
}

.CloseButton {
  display: block;
  margin: 1rem;
}

.SlotDiv {
  display: contents;
}

HTML

<html>
  <head>
    <title>React Google Maps - College Picker App</title>

    <link rel="stylesheet" type="text/css" >hre<f=&qu>ot;<./st>yle.c<ss" /
  ></hea>d
  b<ody
    div id="root"/di><v
    s>cri<pt ty>p<e=&qu>quot; src="./index"/script
  /body
/htmlindex.html

Try Sample

Clone Sample

Git and Node.js are required to run this sample locally. Follow these instructions to install Node.js and NPM. The following commands clone, install dependencies and start the sample application.

  git clone -b sample-rgm-college-picker https://github.com/googlemaps/js-samples.git
  cd js-samples
  npm i
  npm start

Other samples can be tried by switching to any branch beginning with sample-SAMPLE_NAME.

  git checkout sample-SAMPLE_NAME
  npm i
  npm start