TomTom Maps for JavaScript
    Preparing search index...

    Class UserEvents<T, WHERE_SCOPE>

    Event handling interface for map features.

    Provides a simple API for attaching and removing event handlers for user interactions with map features such as clicks, hovers, and context menus. Each map module (POIs, Routing, Places, etc.) exposes an events property that returns a UserEvents instance.

    Supported Event Types:

    • click: User clicks/taps on a feature
    • contextmenu: User right-clicks on a feature (or long-press on mobile)
    • hover: Mouse enters a feature
    • long-hover: Mouse hovers over feature for configured duration (300-800ms)

    Event Handler Signature:

    (feature: T, lngLat: LngLat, features: T[]) => void
    

    Parameters:

    • feature: The primary feature under the cursor
    • lngLat: Geographic coordinates of the event
    • features: All features at this location (when multiple overlap)

    Key Features:

    • Automatic cursor management (pointer on hover)
    • Smart event handling for overlapping features
    • Configurable hover delays
    • Memory-safe cleanup when removing handlers
    // POI click handler
    const pois = map.pois();
    pois.events.on('click', (feature, lngLat) => {
    console.log('Clicked POI:', feature.properties.name);
    console.log('Location:', lngLat);
    showInfoWindow(feature.properties);
    });

    // Route waypoint hover
    const routing = map.routing();
    routing.events.waypoints.on('hover', (waypoint) => {
    showTooltip(`Waypoint ${waypoint.properties.index}`);
    });

    // Long-hover for detailed info
    pois.events.on('long-hover', (feature) => {
    loadAndShowDetailedInfo(feature.properties.id);
    });

    // Context menu (right-click)
    routing.events.mainLines.on('contextmenu', (route, lngLat) => {
    showContextMenu(lngLat, [
    { label: 'Add waypoint here', action: () => addWaypoint(lngLat) },
    { label: 'View route details', action: () => showDetails(route) }
    ]);
    });

    // Remove all click handlers
    pois.events.off('click');
    // Complete interaction example
    const places = map.places();

    // Show name on hover
    places.events.on('hover', (place) => {
    tooltip.show(place.properties.name);
    });

    // Show details on click
    places.events.on('click', (place, lngLat) => {
    sidebar.show({
    title: place.properties.name,
    address: place.properties.address.freeformAddress,
    coordinates: lngLat
    });
    });

    // Cleanup on component unmount
    onUnmount(() => {
    places.events.off('hover');
    places.events.off('click');
    });

    Type Parameters

    • T = MapGeoJSONFeature

      The feature type returned in event handlers (extends MapGeoJSONFeature)

    • WHERE_SCOPE = never
    Index
    • Remove all event handlers for a specific event type.

      Unregisters the callback function for the specified event type, stopping further event notifications. This is important for cleanup to prevent memory leaks and unwanted behavior.

      Parameters

      • type: EventType

        The type of event to stop listening for

      Returns void

      Cleanup Behavior:

      • Removes all handlers for the specified event type — to remove a single handler, call the unsubscribe function returned by on
      • Other event types remain active
      • Resets cursor behavior for this module
      • Safe to call multiple times (no error if no handler exists)
      • Does not affect other modules' event handlers

      When to Use:

      • Component unmounting/cleanup
      • Switching between interaction modes
      • Temporarily disabling interactions
      • Replacing an existing handler (call off() then on())

      Best Practices:

      • Always clean up event handlers when component unmounts
      • Remove handlers before removing features from the map
      • Use framework lifecycle hooks for automatic cleanup
      // Remove click handlers
      module.events.off('click');

      // Remove all handlers
      module.events.off('click');
      module.events.off('hover');
      module.events.off('long-hover');
      module.events.off('contextmenu');
      // React component cleanup
      useEffect(() => {
      const pois = map.pois();

      pois.events.on('click', handlePoiClick);
      pois.events.on('hover', handlePoiHover);

      return () => {
      // Cleanup on unmount
      pois.events.off('click');
      pois.events.off('hover');
      };
      }, [map]);
      // Replace handler
      module.events.off('click'); // Remove old handler
      module.events.on('click', newHandler); // Add new handler

      // Disable interactions temporarily
      const savedHandler = currentHandler;
      module.events.off('click'); // Disable
      // ... later ...
      module.events.on('click', savedHandler); // Re-enable
    • Register an event handler for user interactions with map features.

      Attaches a callback function that will be invoked when users interact with features in this module (e.g., clicking on a POI, hovering over a route).

      Parameters

      • type: EventType

        The type of event to listen for (click, contextmenu, hover, long-hover)

      • handler: UserEventHandler<T>

        Callback function invoked when the event occurs

      Returns () => void

      An unsubscribe function that removes the handler registered by this call.

      Handler Parameters:

      • feature: The primary feature that triggered the event
      • lngLat: Geographic coordinates [longitude, latitude] of the event
      • features: The features from this module at the event location, de-duplicated (for overlapping features within the module). To inspect features across all modules, query map.mapLibreMap.queryRenderedFeatures(...) directly — see UserEventHandler.

      Behavior:

      • Multiple handlers per event type are supported — each on() adds a handler (it does not replace existing ones) and all of them fire. To remove one, call the unsubscribe this returns; to clear them all, use off(type).
      • Handlers are preserved across map style changes
      • Cursor automatically changes to pointer on hover
      • Events respect module visibility (hidden features don't trigger events)

      Performance:

      • Hover events use spatial indexing for fast lookup
      • Long-hover has configurable delay to prevent accidental triggers
      • Event handlers should be lightweight to maintain smooth interaction
      // Basic click handler
      module.events.on('click', (feature, lngLat, features) => {
      console.log('Clicked feature:', feature.properties);
      console.log('Location:', lngLat);
      console.log('All features here:', features.length);
      });

      // Hover with tooltip
      module.events.on('hover', (feature) => {
      const name = feature.properties.name || 'Unnamed';
      tooltip.show(name);
      });

      // Long-hover for detailed preview
      module.events.on('long-hover', (feature) => {
      // Only triggered after hovering for 300-800ms
      loadPreview(feature.properties.id);
      });

      // Right-click context menu
      module.events.on('contextmenu', (feature, lngLat) => {
      event.preventDefault(); // Prevent browser context menu
      showCustomMenu(lngLat, feature);
      });
      // Route-specific handlers
      const routing = map.routing();

      // Handle route line clicks
      routing.events.mainLines.on('click', (route) => {
      highlightRoute(route.properties.routeID);
      showRouteSummary(route.properties.summary);
      });

      // Handle waypoint interactions
      routing.events.waypoints.on('hover', (waypoint) => {
      const index = waypoint.properties.index;
      showTooltip(`Stop ${index + 1}`);
      });
    • Narrows these events to part of what they cover, returning a UserEvents over just that part.

      Two things can be narrowed. A feature predicate keeps only the features you care about — available on every module, since only the module's own data can tell a major incident from a minor one. A layer scope keeps only part of the map's layers; the SDK offers this where a stable, typed vocabulary for those layers exists, which today means BaseMapModule's layer groups.

      A new instance, rather than this one narrowed in place: callers hold events and narrow it more than once, and mutating would make the second where() mean "first AND second" while leaving the surface it came from silently scoped — and its config overridden.

      Narrowing on both axes is one call, not two — BaseMapModule's scope object takes a features predicate alongside its layerGroups. A further where() does intersect with this one, but two feature predicates read better as a single a(f) && b(f).

      Parameters

      • scope: EventScope<T, WHERE_SCOPE>

        See EventScope — a predicate over this scope's feature type, or, where the module supports one, a scope object such as { layerGroups }.

      • Optionalconfig: EventHandlerCursorConfig

        Event configuration for handlers registered through the returned instance. Each scope can carry its own, which is how two parts of one module get different hover cursors. Defaults to the configuration this instance already uses.

      Returns UserEvents<T, WHERE_SCOPE>

      // Feature scope: only major incidents are clickable.
      trafficIncidents.events.where((incident) => incident.properties.magnitude === 'major')
      .on('click', showIncidentDetails);

      // Layer scope with its own cursor, on the base map.
      baseMap.events
      .where({ layerGroups: { mode: 'include', names: ['roadLabels'] } }, { cursorOnHover: 'pointer' })
      .on('click', showRoadName);

      // A named scope, narrowed by a predicate.
      routing.events.tunnels.where((section) => section.properties.lengthInMeters > 500)
      .on('click', showLongTunnel);