reactjsgoogle-maps-api-3react-google-maps-api

Replace google map api default info window with custom


When you click on a location inside the map using the Google Maps API it displays an info window with the name, address, and link to view it on Google Maps.

enter image description here

Is there a way to override this event and supply it with my own data & styles?

So far I added an onClick listener that looks for events with a placeId property, grabs data for that place, and displays it in an InfoWindow component.

However, this doesn't prevent the default window from opening. It still opens and then gets covered by mine. Works but not exactly what I'm hoping to accomplish.

I either want to completely prevent the default one from showing, OR, apply my changes directly to it and not need to have this separate event handler.

async function handleOnClick(event) {
    setContent(undefined);
    const latitude = event.latLng.lat();
    const longitude = event.latLng.lng();

    if (event.placeId) {
      const request = {
        placeId: event.placeId,
        fields: ['name', 'formatted_address', 'place_id', 'geometry', 'photo'],
      };

      const placesService = new google.maps.places.PlacesService(map);

      placesService.getDetails(request, (place, status) => {
        if (status === 'OK') {
          const info = (
            <InfoWindow
              position={{
                lat: place?.geometry?.location?.lat(),
                lng: place?.geometry?.location?.lng(),
              }}
              onCloseClick={() => setContent(undefined)}
            >
              <div>
                <h3>{place.name}</h3>
                <div className='photo-gallery'>
                  {place?.photos.map((photo) => {
                    return <img className='photo' src={photo.getUrl()} />;
                  })}
                </div>
              </div>
            </InfoWindow>
          );

          setContent(info);
        }
      });
    }
  }

I doing this in react with the @react-google-maps/api library


Solution

  • Use event.stop() method for POI click event to prevent the Info Window from showing while still processing the Place ID (EDITED)

    There's an option on MapOptions called clickableIcons where you can set to false, which would disable the click capability on the default POI icons/markers.

    Unfortunately, this would also disable the feature where you can have the placeId of the icon using the map.addListener()

    What I would suggest is for you to file a Feature Request that would enable developers to modify the content of the default POIs when clicked. https://developers.google.com/maps/support#issue_tracker

    But since the Google Maps API currently does not have this feature, one workaround (Thanks to OPs comment), is to turn off the event with event.stop once you have the place ID on POI click.

    Here's how it should work using the code OP provided:

    Create an Info Window state hook to store the contents later on and generate the Component.

    const [infoWindow, setInfoWindow] = React.useState(null);
    

    Inside the onLoad callback definition, you check if the Place ID is available. Then if is true, you fire the event.stop() method to prevent the default Info Window from showing and proceed in processing the fetched Place ID with Places API Place Details and put those data on the custom Info Window you will render on the clicked POI icon.

    const onLoad = React.useCallback(function callback(map) {
      map.addListener("click", (event) => {
        if (event.placeId) {
          // once the check for Place ID is done, 
          // fire the event.stop() here to prevent the default Info Window from showing
          event.stop();
          
          // Proceed in processing the Place Details request
          // and create the custom Info Window based on the fetched data
          const request = {
            placeId: event.placeId,
            fields: [
              "name",
              "formatted_address",
              "place_id",
              "geometry",
              "photo",
            ],
          };
    
          const placesService = new google.maps.places.PlacesService(map);
    
          placesService.getDetails(request, (place, status) => {
            if (status === "OK") {
              // store the Info Window component inside a variable,
              // This will be put inside the Info Window state hook later.
              const info = (
                <InfoWindow
                  position={{
                    lat: place?.geometry?.location?.lat(),
                    lng: place?.geometry?.location?.lng(),
                  }}
                  onCloseClick={() => setInfoWindow(null)}
                >
                  <div>
                    <h3>{place.name}</h3>
                    <div className="photo-gallery">
                      {place?.photos.map((photo) => {
                        return <img className="photo" src={photo.getUrl()} />;
                      })}
                    </div>
                  </div>
                </InfoWindow>
              );
              // Update the Info Window state hook here.
              setInfoWindow(info);
            }
          });
        }
      });
    }, []);
    

    Then you just put the infoWindow state hook inside the GoogleMap component to show the Info Window when the details are provided.

    return isLoaded ? (
      <GoogleMap
        mapContainerStyle={containerStyle}
        center={center}
        zoom={15}
        onLoad={onLoad}
        onUnmount={onUnmount}
      >
        {infoWindow ? infoWindow : null}
      </GoogleMap>
    ) : (
      <></>
    );
    

    After all that, it should look something like this:

    enter image description here

    Here's a proof of concept code sandbox that you can try and play around: https://codesandbox.io/p/sandbox/poi-click-infowindow-tfxjjw

    NOTE: Use your own API KEY