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.