Skip to content

Events Reference

The Mapsted Maps JavaScript API exposes 20 typed events. Use on(), off(), and once() to subscribe and unsubscribe.

ts
import * as maps from '@mapsted/maps-js-api';

// Subscribe
maps.on('select', (data) => console.log('Selected entity:', data.entityId));

// Subscribe once
maps.once('load', () => console.log('Map loaded'));

// Unsubscribe
const handler = (data) => { /* ... */ };
maps.on('floorChange', handler);
maps.off('floorChange', handler);

All event names use camelCase. The API normalises wire-protocol names (e.g. MAP_MOUNTED) to their public camelCase equivalents automatically.


Event table

Event namePayload typeFired when
mapMountedvoidThe iframe's React app has mounted. Fires before load.
loadvoidThe map is fully loaded and ready for commands.
selectEntityDataThe user (or the API) selects a map entity.
coordsSelectCoordsDataThe user selects a custom coordinate marker.
floorChangeFloorInfoThe active floor changes (navigation or user tap).
idleChange{ isUserActive: boolean }User activity state toggles (requires idleTime to be set).
mapOverlayMarkerSelect{ mapOverlayId: string; name?: string; marker?: string; lat?: number; lng?: number }The user taps a map overlay marker; payload is an object containing mapOverlayId plus any metadata set on the marker.
zoomLevelChange{ zoomLevel: number }The map zoom level changes.
mapCenterChange{ mapCenter: [number, number] }The map viewport centre changes. Payload is [longitude, latitude].
promotionClickPromotionDataThe user clicks a promotion card or banner.
navigationStartNavigationDataA wayfinding route begins rendering.
searchText{ searchText: string }The user types in the search bar.
detailsViewEntityDataThe entity details panel opens.
promotionDetailsPromotionDataThe promotion details view opens.
accessibilityChange{ enabled: boolean }Accessibility routing mode is toggled via setAccessibilityMode().
themeChangeThemeChangePayloadA theme is applied via setTheme(), CMS remote push, or user-toggled UI.
boostComplete{ type: 'FLOOR' | 'SELECT' | 'ROUTING' }A boost lifecycle has settled — floor change applied, entity selected, or itinerary created.
all{ type: string; [key: string]: unknown }Fires for all public events including protocolError; internal reply messages are excluded. Useful for debugging.
protocolErrorProtocolErrorPayloadA postMessage protocol error occurred between the API and the iframe.
buildingChangeBuildingChangePayloadThe user navigates to a different building inside a multi-building property. Payload: buildingId (new building) + previousBuildingId (prior building or null).

Event details

mapMounted

Fires when the iframe's React tree mounts. The map data has not yet loaded at this point. In most cases use load (or the onload callback) instead.

ts
maps.once('mapMounted', () => {
  console.log('Iframe React app mounted');
});

load

Fires when the map is fully operational and ready for commands. This is equivalent to the onload callback in InitOptions.

ts
maps.once('load', () => {
  maps.navigateToFloorById(184);
});

select

Fires when an entity is selected — either by the user tapping it or by calling selectEntity(). The payload is an EntityData object.

Payload:

ts
{
  buildingId: string | number;
  floorId: string | number;
  entityId: string | number;
}
ts
maps.on('select', ({ buildingId, floorId, entityId }) => {
  fetchEntityDetails(entityId).then(renderSidebar);
});

Disable the built-in popup with features: { defaultPopup: false } to take full control of the selection UI.


coordsSelect

Fires when a custom coordinate marker (added via setCoordsData()) is tapped by the user.

Payload: CoordsData — the same object that was passed to setCoordsData(), including lat, long, floor, name, html, and marker. Note: lng is accepted as an alias for long when constructing CoordsData objects; both spellings are equivalent.

ts
maps.on('coordsSelect', (coords) => {
  console.log(`Tapped marker at [${coords.lat}, ${coords.long}]`);
});

floorChange

Fires after the active floor changes. Payload is a FloorInfo object.

Payload:

ts
{
  floorId: string | number;
  floorNumber: number;
  longName: Record<string, string>;   // e.g. { en: 'Ground Floor', fr: 'Rez-de-chaussée' }
  shortName: Record<string, string>;  // e.g. { en: 'G', fr: 'RdC' }
}
ts
maps.on('floorChange', (floor) => {
  document.title = `Floor: ${floor.longName['en'] ?? floor.floorNumber}`;
});

idleChange

Fires when user activity state changes. Requires idleTime to be configured in InitOptions or via setIdleTime().

Payload: { isUserActive: boolean }

  • isUserActive: false — user has been inactive for idleTime milliseconds.
  • isUserActive: true — user resumed interaction.
ts
maps.on('idleChange', ({ isUserActive }) => {
  if (!isUserActive) {
    // Show screensaver / return to default view
    maps.applyBoost({ floor: 184 });
  }
});

mapOverlayMarkerSelect

Fires when the user taps a custom overlay marker placed via setMapOverlayMarkers().

Payload:

ts
{
  mapOverlayId: string;  // CMS overlay ID of the tapped marker
  name?: string;         // name set on the MapOverlayMarker, if any
  marker?: string;       // marker HTML/URL set on the MapOverlayMarker, if any
  lat?: number;          // latitude set on the MapOverlayMarker, if any
  lng?: number;          // longitude set on the MapOverlayMarker, if any
}
ts
maps.on('mapOverlayMarkerSelect', ({ mapOverlayId, name, lat, lng }) => {
  console.log('Overlay tapped:', mapOverlayId, name ?? '');
  openOverlayPanel(mapOverlayId);
});

zoomLevelChange

Fires on every zoom level change.

Payload: { zoomLevel: number } — the new zoom level (10–24).

ts
maps.on('zoomLevelChange', ({ zoomLevel }) => {
  console.log('Zoom:', zoomLevel);
});

mapCenterChange

Fires when the map viewport centre moves.

Payload: { mapCenter: [number, number] }[longitude, latitude] in WGS84.

ts
maps.on('mapCenterChange', ({ mapCenter }) => {
  const [lng, lat] = mapCenter;
  updateMinimap(lng, lat);
});

promotionClick

Fires when the user clicks a promotion card or banner.

Payload: PromotionData — contains an optional entity: EntityData and additional CMS metadata fields.

ts
maps.on('promotionClick', (promo) => {
  if (promo.entity) analytics.track('promo_click', promo.entity);
});

Fires when a wayfinding route begins rendering on the map.

Payload:

ts
{
  routing?: string;       // e.g. "95:3595,95:3818"
  routeOptions?: string;  // e.g. "IncludeElevators"
}
ts
maps.on('navigationStart', ({ routing }) => {
  analytics.track('route_started', { routing });
});

searchText

Fires as the user types in the built-in search bar. Useful for logging or triggering side-effects.

Payload: { searchText: string }

ts
maps.on('searchText', ({ searchText }) => {
  if (searchText.length > 2) suggestEntities(searchText);
});

detailsView

Fires when the entity details panel opens.

Payload: EntityData — same shape as the select payload.

ts
maps.on('detailsView', (entity) => {
  preloadEntityContent(entity.entityId);
});

promotionDetails

Fires when the user opens the promotion details view (expanded promotion info).

Payload: PromotionData

ts
maps.on('promotionDetails', (promo) => {
  analytics.track('promo_details_opened', promo);
});

accessibilityChange

Fires when accessibility routing mode is toggled via setAccessibilityMode(). New in V3.

Payload: { enabled: boolean }

Client-side synthetic event. Unlike most other events, accessibilityChange is not emitted from the map iframe. It is synthesised on the JS-API side immediately after the setAccessibilityMode() call resolves, so handlers reflect the requested state — not necessarily the state the iframe has finished rendering. For strict post-render confirmation, await getState() after the next paint.

ts
maps.on('accessibilityChange', ({ enabled }) => {
  document.querySelector('#a11y-toggle').setAttribute('aria-pressed', String(enabled));
});

all

Fires for all public events including protocolError; internal reply messages (e.g. GET_FLOORS_RESPONSE) are excluded. The payload is a generic object with a type field containing the event name. Useful for logging, analytics pipelines, and debugging.

Payload: { type: string; [key: string]: unknown }

ts
maps.on('all', ({ type, ...rest }) => {
  analytics.track(`map_event_${type}`, rest);
});

protocolError

Fires when the postMessage protocol between the API and the iframe encounters an error — for example, a malformed message or an unexpected message type.

Payload:

ts
{
  reason: string;
  code: string;
  message: string;
  details: Record<string, unknown>;
}
ts
maps.on('protocolError', (error) => {
  console.error('[Mapsted protocol error]', error.code, error.message);
  Sentry.captureException(new Error(error.message), { extra: error.details });
});

themeChange

Fires when a theme is applied — via setTheme(), via a CMS remote push, or via a user-toggled UI control. Payload is a ThemeChangePayload carrying both the resolved Theme object and its themeId.

Payload:

ts
{
  theme: Theme;       // full theme object that was applied
  themeId: string;    // e.g. "mapstedDark" or a CMS ObjectId string
}
ts
maps.on('themeChange', ({ theme, themeId }) => {
  console.log('Theme switched:', themeId, 'dark?', theme.dark);
  document.documentElement.dataset.mapTheme = themeId;
});

Use getThemes() to enumerate the property's available themes before driving a switcher UI.


boostComplete

Fires once after a boost lifecycle settles. The payload type indicates which boost completed:

  • 'FLOOR' — a floor change requested by a boost has finished applying.
  • 'SELECT' — an entity selection requested by a boost has finished.
  • 'ROUTING' — an itinerary requested by a boost has been created.

Useful for hiding loading indicators or chaining a follow-up action after a boost completes.

Payload:

ts
{
  type: 'FLOOR' | 'SELECT' | 'ROUTING';
}
ts
maps.on('boostComplete', ({ type }) => {
  if (type === 'ROUTING') hideRouteSpinner();
});

See applyBoost, createBoostSelect, and createBoostRouting for the boost APIs that drive this event.


buildingChange

Fires when the user navigates from one building to another inside a multi-building property (e.g. an airport with multiple terminals, or a campus with multiple structures). The map dispatches this once per building transition — it never fires on the initial map load, and never fires if the active building has not actually changed.

Payload (BuildingChangePayload):

ts
{
  buildingId: number;             // positive integer — the building entered
  previousBuildingId: number | null; // prior building, or null on first entry
}
ts
maps.on('buildingChange', ({ buildingId, previousBuildingId }) => {
  console.log('Entered building', buildingId);
  if (previousBuildingId !== null) {
    console.log('Left building', previousBuildingId);
  }
  // e.g. update a terminal indicator in your host UI
  updateBuildingIndicator(buildingId);
});

V2 migration

V2 used addEventListener / removeEventListener. These still work via a compatibility shim that emits a console.warn deprecation notice. Migrate to on / off / once before the shim is removed in the next major release.

ts
// V2 (deprecated, works via shim)
maps.addEventListener('select', handler);

// Current (correct)
maps.on('select', handler);

See Changelog for full migration details.