This is the documentation of version 1.0.0-rc.3. Go to the latest version, 1.0.0-rc.5.
TomTom Maps for JavaScript
    Preparing search index...

    Class UserEvents<T, WHERE_SCOPE>

    The user events of a map module's features.

    Use it to attach and remove 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.

    The event types are:

    • click - The user clicks or taps a feature.
    • contextmenu - The user right-clicks a feature, or long-presses it on mobile.
    • hover - The mouse enters a feature.
    • hover-move - The mouse moves along the feature it is already on.
    • long-hover - The mouse hovers over a feature for the configured duration (300-800ms).

    A handler has this signature:

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

    It receives:

    • feature - The primary feature under the cursor.
    • lngLat - The geographic coordinates of the event.
    • features - All features at this location, when several overlap.

    The SDK manages the cursor (pointer on hover) and handles overlapping features. Hover delays are configurable, and removing handlers cleans up memory safely.

    // POI click handler
    const pois = await POIsModule.get(map);
    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 = await RoutingModule.create(map);
    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 = await PlacesModule.create(map);

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

    // Show details on click
    places.events.on('click', (place, lngLat) => {
    sidebar.show({
    title: place.properties.title,
    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

    Hierarchy (View Summary)

    Index
    • Removes all event handlers for an event type.

      This stops further event notifications for that type. Clean up this way to prevent memory leaks and unwanted behaviour.

      Parameters

      • type: EventType

        The event type to stop listening for.

      Returns void

      • It removes all of this module's handlers for the event type on the features these events cover, whichever of the module's events objects registered them. So places.events.places.off('click') also takes a places.events.on('click', …) handler off the pins, while that handler keeps firing on connections.
      • To remove a single handler, call the unsubscribe function on returns.
      • Other event types and other modules' handlers stay active. It also resets this module's cursor behaviour, and you can safely call it more than once, even when no handler exists.

      Always call it when a component unmounts, ideally from a framework lifecycle hook. Also use it to switch between interaction modes, to disable interactions temporarily, or to replace a handler by calling off() and then on(). Remove handlers before you remove features from the map.

      // Remove click handlers
      module.events.off('click');

      // Remove all handlers
      module.events.off('click');
      module.events.off('hover');
      module.events.off('hover-move');
      module.events.off('long-hover');
      module.events.off('contextmenu');
      // React component cleanup, with `pois` from `await POIsModule.get(map)`
      useEffect(() => {
      pois.events.on('click', handlePoiClick);
      pois.events.on('hover', handlePoiHover);

      return () => {
      // Cleanup on unmount
      pois.events.off('click');
      pois.events.off('hover');
      };
      }, [pois]);
      // 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
    • Registers a handler for user interactions with this module's features, such as clicking a POI or hovering over a route.

      Parameters

      • type: EventType

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

      • handler: UserEventHandler<T>

        The function called when the event occurs.

      Returns () => void

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

      The handler receives:

      • feature - The primary feature that triggered the event.
      • lngLat - The geographic coordinates of the event, as a MapLibre LngLat (lngLat.lng, lngLat.lat).
      • features - This module's features at the event location, de-duplicated for overlapping features within the module. To inspect features across all modules, query map.mapLibreMap.queryRenderedFeatures(...) directly, as UserEventHandler shows.

      Note that:

      • Each on() adds a handler and does not replace existing ones, so all of them fire. To remove one, call the unsubscribe function this returns. To clear them all, use off(type).
      • Handlers survive map style changes.
      • The cursor changes to a pointer on hover.
      • Hidden features don't trigger events, since events respect module visibility.
      • Hover events use spatial indexing for fast lookup.
      • Long-hover has a configurable delay to prevent accidental triggers.
      • Keep handlers 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) => {
      showCustomMenu(lngLat, feature);
      });
      // Route-specific handlers
      const routing = await RoutingModule.create(map);

      // Handle route line clicks
      routing.events.mainLines.on('click', (route) => {
      highlightRoute(route.properties.index);
      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, and returns a UserEvents over just that part.

      You can narrow in two ways. A feature predicate keeps only the features you care about. Every module offers it, 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 it where a stable, typed vocabulary for those layers exists, which today means BaseMapModule's layer groups.

      A predicate decides on the top-most feature under the pointer. A feature it rejects stays inert: it keeps the map cursor, takes no hover or click state, and the handler doesn't run, even when a feature the predicate accepts lies beneath it.

      It returns a new instance rather than narrowing this one in place. Callers narrow events more than once, and mutating would make the second where() mean "first AND second". It would also leave the surface it came from silently scoped, with its config overridden.

      Narrowing on both axes takes one call, since 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>

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

      • Optionalconfig: EventHandlerConfig

        The 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.magnitudeOfDelay === 'major')
      .on('click', showIncidentDetails);

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

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