diff --git a/docs/api-reference/components/advanced-marker.md b/docs/api-reference/components/advanced-marker.md
index e9162048..d16bae62 100644
--- a/docs/api-reference/components/advanced-marker.md
+++ b/docs/api-reference/components/advanced-marker.md
@@ -203,6 +203,9 @@ marker will be clickable and will be interactive for accessibility purposes
By default, this will automatically be set to true when the `onClick` prop
is specified.
+It is also automatically set to true when `onKeyDown` or `onKeyUp` is
+specified.
+
#### `draggable`: boolean
Controls if the marker can be repositioned by dragging.
@@ -223,6 +226,14 @@ specified in the position can't be dragged.
This event is fired when the marker is clicked.
+#### `onKeyDown`: (e: KeyboardEvent) => void
+
+This event is fired when a key is pressed while the marker is focused.
+
+#### `onKeyUp`: (e: KeyboardEvent) => void
+
+This event is fired when a pressed key is released while the marker is focused.
+
#### `onMouseEnter`: (e: [google.maps.MapMouseEvent['domEvent']][gmp-map-mouse-ev-dom]) => void
This event is fired when the mouse enters the marker.
diff --git a/src/components/__tests__/advanced-marker.test.tsx b/src/components/__tests__/advanced-marker.test.tsx
index 197a9fa5..e6727436 100644
--- a/src/components/__tests__/advanced-marker.test.tsx
+++ b/src/components/__tests__/advanced-marker.test.tsx
@@ -1,7 +1,12 @@
import React from 'react';
import {initialize, mockInstances} from '@googlemaps/jest-mocks';
-import {cleanup, queryByTestId, render} from '@testing-library/react';
+import {
+ cleanup,
+ fireEvent,
+ queryByTestId,
+ render
+} from '@testing-library/react';
import '@testing-library/jest-dom';
import {AdvancedMarker, AdvancedMarkerAnchorPoint} from '../advanced-marker';
@@ -195,8 +200,53 @@ describe('map and marker-library loaded', () => {
expect((marker.content as HTMLElement).style.cursor).toBe('');
});
+ test('binds gmp-click events to onClick', async () => {
+ const handleClick = jest.fn();
+
+ render(
+
+ );
+
+ const marker = await waitForMockInstance(
+ google.maps.marker.AdvancedMarkerElement
+ );
+
+ const clickEvent = new Event('gmp-click');
+ fireEvent(marker, clickEvent);
+
+ expect(handleClick).toHaveBeenCalledWith(clickEvent);
+ expect(marker.gmpClickable).toBe(true);
+ });
+
+ test('binds keyboard events and infers clickability from them', async () => {
+ const handleKeyDown = jest.fn();
+ const handleKeyUp = jest.fn();
+
+ render(
+
+ );
+
+ const marker = await waitForMockInstance(
+ google.maps.marker.AdvancedMarkerElement
+ );
+
+ expect(marker.gmpClickable).toBe(true);
+
+ const keyDownEvent = new KeyboardEvent('keydown', {key: 'Enter'});
+ const keyUpEvent = new KeyboardEvent('keyup', {key: ' '});
+
+ fireEvent(marker, keyDownEvent);
+ fireEvent(marker, keyUpEvent);
+
+ expect(handleKeyDown).toHaveBeenCalledWith(keyDownEvent);
+ expect(handleKeyUp).toHaveBeenCalledWith(keyUpEvent);
+ });
+
test.todo('marker should work with options');
- test.todo('marker should have a click listener');
describe('anchoring with modern API', () => {
beforeEach(() => {
diff --git a/src/components/advanced-marker.tsx b/src/components/advanced-marker.tsx
index a240b273..10a9c210 100644
--- a/src/components/advanced-marker.tsx
+++ b/src/components/advanced-marker.tsx
@@ -75,7 +75,9 @@ export type AdvancedMarkerAnchorPoint =
(typeof AdvancedMarkerAnchorPoint)[keyof typeof AdvancedMarkerAnchorPoint];
type AdvancedMarkerEventProps = {
- onClick?: (e: google.maps.MapMouseEvent) => void;
+ onClick?: (e: google.maps.marker.AdvancedMarkerClickEvent) => void;
+ onKeyDown?: (e: KeyboardEvent) => void;
+ onKeyUp?: (e: KeyboardEvent) => void;
onMouseEnter?: (e: google.maps.MapMouseEvent['domEvent']) => void;
onMouseLeave?: (e: google.maps.MapMouseEvent['domEvent']) => void;
onDrag?: (e: google.maps.MapMouseEvent) => void;
@@ -211,6 +213,8 @@ function useAdvancedMarker(props: AdvancedMarkerProps) {
const {
children,
onClick,
+ onKeyDown,
+ onKeyUp,
className,
onMouseEnter,
onMouseLeave,
@@ -296,8 +300,8 @@ function useAdvancedMarker(props: AdvancedMarkerProps) {
else marker.gmpDraggable = false;
}, [marker, draggable, onDrag, onDragEnd, onDragStart]);
- // set gmpClickable from props (when unspecified, it's true if the onClick or one of
- // the hover events callbacks are specified)
+ // set gmpClickable from props (when unspecified, it's true if any interactive
+ // event callbacks are specified)
useEffect(() => {
if (!marker) return;
@@ -306,7 +310,11 @@ function useAdvancedMarker(props: AdvancedMarkerProps) {
const gmpClickable =
clickable !== undefined
? clickable
- : Boolean(onClick) || Boolean(onMouseEnter) || Boolean(onMouseLeave);
+ : Boolean(onClick) ||
+ Boolean(onKeyDown) ||
+ Boolean(onKeyUp) ||
+ Boolean(onMouseEnter) ||
+ Boolean(onMouseLeave);
// gmpClickable is only available in beta version of the
// maps api (as of 2024-10-10)
@@ -319,13 +327,23 @@ function useAdvancedMarker(props: AdvancedMarkerProps) {
marker.content.style.pointerEvents = gmpClickable ? 'all' : 'none';
marker.content.style.cursor = gmpClickable && onClick ? 'pointer' : '';
}
- }, [marker, clickable, onClick, onMouseEnter, onMouseLeave]);
+ }, [
+ marker,
+ clickable,
+ onClick,
+ onKeyDown,
+ onKeyUp,
+ onMouseEnter,
+ onMouseLeave
+ ]);
useMapsEventListener(marker, 'drag', onDrag);
useMapsEventListener(marker, 'dragstart', onDragStart);
useMapsEventListener(marker, 'dragend', onDragEnd);
useDomEventListener(marker, 'gmp-click', onClick);
+ useDomEventListener(marker, 'keydown', onKeyDown);
+ useDomEventListener(marker, 'keyup', onKeyUp);
useDomEventListener(marker, 'mouseenter', onMouseEnter);
useDomEventListener(marker, 'mouseleave', onMouseLeave);