Appearance
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 name | Payload type | Fired when |
|---|---|---|
mapMounted | void | The iframe's React app has mounted. Fires before load. |
load | void | The map is fully loaded and ready for commands. |
select | EntityData | The user (or the API) selects a map entity. |
coordsSelect | CoordsData | The user selects a custom coordinate marker. |
floorChange | FloorInfo | The 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]. |
promotionClick | PromotionData | The user clicks a promotion card or banner. |
navigationStart | NavigationData | A wayfinding route begins rendering. |
searchText | { searchText: string } | The user types in the search bar. |
detailsView | EntityData | The entity details panel opens. |
promotionDetails | PromotionData | The promotion details view opens. |
accessibilityChange | { enabled: boolean } | Accessibility routing mode is toggled via setAccessibilityMode(). |
themeChange | ThemeChangePayload | A 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. |
protocolError | ProtocolErrorPayload | A postMessage protocol error occurred between the API and the iframe. |
buildingChange | BuildingChangePayload | The 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 foridleTimemilliseconds.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);
});navigationStart
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,
accessibilityChangeis not emitted from the map iframe. It is synthesised on the JS-API side immediately after thesetAccessibilityMode()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.