Select platform: [Android](https://developers.google.com/maps/documentation/android-sdk/dds-boundaries/handle-events.md.txt "View this page for the Android platform docs.") [iOS](https://developers.google.com/maps/documentation/ios-sdk/dds-boundaries/handle-events.md.txt "View this page for the iOS platform docs.") [JavaScript](https://developers.google.com/maps/documentation/javascript/dds-boundaries/handle-events.md.txt "View this page for the JavaScript platform docs.")

<br />

## Overview

Make a feature layer respond to `mousemove` and `click` events, and use
them to return information about the boundary that was clicked. This information
includes ID, display name, and feature type. The following example map shows the
boundaries for Administrative Area Level 2, and has event handling code that
styles polygons based on user interaction (`mousemove` changes the border
thickness, `click` shades the background color and causes an info window to
display).


<iframe src="https://maps-docs-team.web.app/samples/boundaries-click/dist/" allow="fullscreen; fullscreen"></iframe>

## Enable feature layer events

Take the following steps to enable events on a feature layer:

1. Register a feature layer for event notifications by calling the
   `addListener()` function on the feature layer for each event you want to
   register. In this example the map also gets a listener.


   ### TypeScript

   ```typescript
   // Add the feature layer.
   featureLayer = innerMap.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2');

   // Add the event listeners for the feature layer.
   featureLayer.addListener('click', handleClick);
   featureLayer.addListener('mousemove', handleMouseMove);

   // Map event listener.
   innerMap.addListener('mousemove', () => {
       // If the map gets a mousemove, that means there are no feature layers
       // with listeners registered under the mouse, so we clear the last
       // interacted feature ids.
       if (lastInteractedFeatureIds?.length) {
           lastInteractedFeatureIds = [];
           featureLayer.style = applyStyle;
       }
   });
   ```

   ### JavaScript

   ```javascript
   // Add the feature layer.
   featureLayer = innerMap.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2');

   // Add the event listeners for the feature layer.
   featureLayer.addListener('click', handleClick);
   featureLayer.addListener('mousemove', handleMouseMove);

   // Map event listener.
   innerMap.addListener('mousemove', () => {
       // If the map gets a mousemove, that means there are no feature layers
       // with listeners registered under the mouse, so we clear the last
       // interacted feature ids.
       if (lastInteractedFeatureIds?.length) {
           lastInteractedFeatureIds = [];
           featureLayer.style = applyStyle;
       }
   });
   ```

   <br />

2. Add event handler code to style the selected polygon based on the type of
   interaction.


   ### TypeScript

   ```typescript
   function handleClick(event: google.maps.FeatureMouseEvent) {
       lastClickedFeatureIds = event.features.map(
           (f) => (f as google.maps.PlaceFeature).placeId
       );
       lastInteractedFeatureIds = [];
       featureLayer.style = applyStyle;
       void createInfoWindow(event);
   }

   function handleMouseMove(event: google.maps.FeatureMouseEvent) {
       lastInteractedFeatureIds = event.features.map(
           (f) => (f as google.maps.PlaceFeature).placeId
       );
       featureLayer.style = applyStyle;
   }
   ```

   ### JavaScript

   ```javascript
   function handleClick(event) {
       lastClickedFeatureIds = event.features.map((f) => f.placeId);
       lastInteractedFeatureIds = [];
       featureLayer.style = applyStyle;
       void createInfoWindow(event);
   }

   function handleMouseMove(event) {
       lastInteractedFeatureIds = event.features.map((f) => f.placeId);
       featureLayer.style = applyStyle;
   }
   ```

   <br />

3. Use a feature style function to apply styles. The feature style function
   shown here conditionally applies style based on the type of interaction. Three
   styles are defined here: one to make the border bold on `mousemove`, one to
   change the background and show an info window on `click`, and a default style.


   ### TypeScript

   ```typescript
   // Define styles.
   // Stroke and fill with minimum opacity value.
   const styleDefault = {
       strokeColor: '#810FCB',
       strokeOpacity: 1.0,
       strokeWeight: 2.0,
       fillColor: 'white',
       fillOpacity: 0.1, // Polygons must be visible to receive events.
   };
   // Style for the clicked polygon.
   const styleClicked = {
       ...styleDefault,
       fillColor: '#810FCB',
       fillOpacity: 0.5,
   };
   // Style for polygon on mouse move.
   const styleMouseMove = {
       ...styleDefault,
       strokeWeight: 4.0,
   };

   // Apply styles using a feature style function.
   function applyStyle(params: google.maps.FeatureStyleFunctionOptions) {
       const placeId = (params.feature as google.maps.PlaceFeature).placeId;
       if (lastClickedFeatureIds.includes(placeId)) {
           return styleClicked;
       }
       if (lastInteractedFeatureIds.includes(placeId)) {
           return styleMouseMove;
       }
       return styleDefault;
   }
   ```

   ### JavaScript

   ```javascript
   // Define styles.
   // Stroke and fill with minimum opacity value.
   const styleDefault = {
       strokeColor: '#810FCB',
       strokeOpacity: 1.0,
       strokeWeight: 2.0,
       fillColor: 'white',
       fillOpacity: 0.1, // Polygons must be visible to receive events.
   };
   // Style for the clicked polygon.
   const styleClicked = {
       ...styleDefault,
       fillColor: '#810FCB',
       fillOpacity: 0.5,
   };
   // Style for polygon on mouse move.
   const styleMouseMove = {
       ...styleDefault,
       strokeWeight: 4.0,
   };

   // Apply styles using a feature style function.
   function applyStyle(params) {
       const placeId = params.feature.placeId;
       if (lastClickedFeatureIds.includes(placeId)) {
           return styleClicked;
       }
       if (lastInteractedFeatureIds.includes(placeId)) {
           return styleMouseMove;
       }
       return styleDefault;
   }
   ```

   <br />

> [!NOTE]
> **Note:** Because only visible features can be interacted with, the default fill style should have a `fillOpacity` of 0.1 or greater.

## Complete example code


### TypeScript

```typescript
let innerMap: google.maps.Map;
let featureLayer: google.maps.FeatureLayer;
let infoWindow: google.maps.InfoWindow;
let lastInteractedFeatureIds: string[] = [];
let lastClickedFeatureIds: string[] = [];

function handleClick(event: google.maps.FeatureMouseEvent) {
    lastClickedFeatureIds = event.features.map(
        (f) => (f as google.maps.PlaceFeature).placeId
    );
    lastInteractedFeatureIds = [];
    featureLayer.style = applyStyle;
    void createInfoWindow(event);
}

function handleMouseMove(event: google.maps.FeatureMouseEvent) {
    lastInteractedFeatureIds = event.features.map(
        (f) => (f as google.maps.PlaceFeature).placeId
    );
    featureLayer.style = applyStyle;
}

async function init() {
    // Request needed libraries.
    const { InfoWindow } = await google.maps.importLibrary('maps');

    // Get the gmp-map element.
    const mapElement = document.querySelector('gmp-map')!;

    // Get the inner map.
    innerMap = mapElement.innerMap;

    // Set map options.
    innerMap.setOptions({
        mapTypeControl: false,
    });

    // Add the feature layer.
    featureLayer = innerMap.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2');

    // Add the event listeners for the feature layer.
    featureLayer.addListener('click', handleClick);
    featureLayer.addListener('mousemove', handleMouseMove);

    // Map event listener.
    innerMap.addListener('mousemove', () => {
        // If the map gets a mousemove, that means there are no feature layers
        // with listeners registered under the mouse, so we clear the last
        // interacted feature ids.
        if (lastInteractedFeatureIds?.length) {
            lastInteractedFeatureIds = [];
            featureLayer.style = applyStyle;
        }
    });

    // Create the infoWindow.
    infoWindow = new InfoWindow();
    // Apply style on load, to enable clicking.
    featureLayer.style = applyStyle;
}

// Helper function for the infoWindow.
async function createInfoWindow(event: google.maps.FeatureMouseEvent) {
    const feature = event.features[0] as google.maps.PlaceFeature;
    if (!feature.placeId) return;

    // Update the info window.
    // Get the place instance from the selected feature.
    const place = await feature.fetchPlace();

    // Create a new div to hold the text content.
    const content = document.createElement('div');

    // Get the text values.
    const nameText = document.createElement('span');
    nameText.textContent = `Display name: ${place.displayName}`;
    const placeIdText = document.createElement('span');
    placeIdText.textContent = `Place ID: ${feature.placeId}`;
    const featureTypeText = document.createElement('span');
    featureTypeText.textContent = `Feature type: ${feature.featureType}`;

    // Append the text to the div.
    content.appendChild(nameText);
    content.appendChild(document.createElement('br'));
    content.appendChild(placeIdText);
    content.appendChild(document.createElement('br'));
    content.appendChild(featureTypeText);

    updateInfoWindow(content, event.latLng);
}

// Define styles.
// Stroke and fill with minimum opacity value.
const styleDefault = {
    strokeColor: '#810FCB',
    strokeOpacity: 1.0,
    strokeWeight: 2.0,
    fillColor: 'white',
    fillOpacity: 0.1, // Polygons must be visible to receive events.
};
// Style for the clicked polygon.
const styleClicked = {
    ...styleDefault,
    fillColor: '#810FCB',
    fillOpacity: 0.5,
};
// Style for polygon on mouse move.
const styleMouseMove = {
    ...styleDefault,
    strokeWeight: 4.0,
};

// Apply styles using a feature style function.
function applyStyle(params: google.maps.FeatureStyleFunctionOptions) {
    const placeId = (params.feature as google.maps.PlaceFeature).placeId;
    if (lastClickedFeatureIds.includes(placeId)) {
        return styleClicked;
    }
    if (lastInteractedFeatureIds.includes(placeId)) {
        return styleMouseMove;
    }
    return styleDefault;
}

// Helper function to create an info window.
function updateInfoWindow(
    content: HTMLElement,
    center: google.maps.LatLng | google.maps.LatLngLiteral | null | undefined
) {
    infoWindow.setContent(content);
    infoWindow.setPosition(center);
    infoWindow.open({
        map: innerMap,
        shouldFocus: false,
    });
}

void init();
```

### JavaScript

```javascript
let innerMap;
let featureLayer;
let infoWindow;
let lastInteractedFeatureIds = [];
let lastClickedFeatureIds = [];

function handleClick(event) {
    lastClickedFeatureIds = event.features.map((f) => f.placeId);
    lastInteractedFeatureIds = [];
    featureLayer.style = applyStyle;
    void createInfoWindow(event);
}

function handleMouseMove(event) {
    lastInteractedFeatureIds = event.features.map((f) => f.placeId);
    featureLayer.style = applyStyle;
}

async function init() {
    // Request needed libraries.
    const { InfoWindow } = await google.maps.importLibrary('maps');

    // Get the gmp-map element.
    const mapElement = document.querySelector('gmp-map');

    // Get the inner map.
    innerMap = mapElement.innerMap;

    // Set map options.
    innerMap.setOptions({
        mapTypeControl: false,
    });

    // Add the feature layer.
    featureLayer = innerMap.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2');

    // Add the event listeners for the feature layer.
    featureLayer.addListener('click', handleClick);
    featureLayer.addListener('mousemove', handleMouseMove);

    // Map event listener.
    innerMap.addListener('mousemove', () => {
        // If the map gets a mousemove, that means there are no feature layers
        // with listeners registered under the mouse, so we clear the last
        // interacted feature ids.
        if (lastInteractedFeatureIds?.length) {
            lastInteractedFeatureIds = [];
            featureLayer.style = applyStyle;
        }
    });

    // Create the infoWindow.
    infoWindow = new InfoWindow();
    // Apply style on load, to enable clicking.
    featureLayer.style = applyStyle;
}

// Helper function for the infoWindow.
async function createInfoWindow(event) {
    const feature = event.features[0];
    if (!feature.placeId) return;

    // Update the info window.
    // Get the place instance from the selected feature.
    const place = await feature.fetchPlace();

    // Create a new div to hold the text content.
    const content = document.createElement('div');

    // Get the text values.
    const nameText = document.createElement('span');
    nameText.textContent = `Display name: ${place.displayName}`;
    const placeIdText = document.createElement('span');
    placeIdText.textContent = `Place ID: ${feature.placeId}`;
    const featureTypeText = document.createElement('span');
    featureTypeText.textContent = `Feature type: ${feature.featureType}`;

    // Append the text to the div.
    content.appendChild(nameText);
    content.appendChild(document.createElement('br'));
    content.appendChild(placeIdText);
    content.appendChild(document.createElement('br'));
    content.appendChild(featureTypeText);

    updateInfoWindow(content, event.latLng);
}

// Define styles.
// Stroke and fill with minimum opacity value.
const styleDefault = {
    strokeColor: '#810FCB',
    strokeOpacity: 1.0,
    strokeWeight: 2.0,
    fillColor: 'white',
    fillOpacity: 0.1, // Polygons must be visible to receive events.
};
// Style for the clicked polygon.
const styleClicked = {
    ...styleDefault,
    fillColor: '#810FCB',
    fillOpacity: 0.5,
};
// Style for polygon on mouse move.
const styleMouseMove = {
    ...styleDefault,
    strokeWeight: 4.0,
};

// Apply styles using a feature style function.
function applyStyle(params) {
    const placeId = params.feature.placeId;
    if (lastClickedFeatureIds.includes(placeId)) {
        return styleClicked;
    }
    if (lastInteractedFeatureIds.includes(placeId)) {
        return styleMouseMove;
    }
    return styleDefault;
}

// Helper function to create an info window.
function updateInfoWindow(content, center) {
    infoWindow.setContent(content);
    infoWindow.setPosition(center);
    infoWindow.open({
        map: innerMap,
        shouldFocus: false,
    });
}

void init();
```

### CSS

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

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

### HTML

```html
<html>
    <head>
        <title>Handle Region Boundary Click Event</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <script>
            // prettier-ignore
            (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: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <gmp-map
            center="39.23,-105.73"
            zoom="8"
            map-id="8b37d7206ccf0121a2634fd5"></gmp-map>
    </body>
</html>
```

### Try Sample

[JSFiddle.net](https://jsfiddle.net/gh/get/library/pure/googlemaps-samples/js-api-samples/tree/main/dist/samples/boundaries-click/jsfiddle)

<br />

[Learn more about events](https://developers.google.com/maps/documentation/javascript/events.md.txt)