Skip to content

Customize Entity Popups with HTML

By default the Mapsted Maps JavaScript API renders a built-in popup when an entity is selected — showing the entity name, category icon, and description from the property data. This guide explains how to replace that popup with your own HTML by supplying an html string on each MapEntity, and how to react to entity-selection events.

Prerequisites

How custom popup HTML works

The API does not accept a popupTemplate callback at init(). Instead, each MapEntity object carries an optional html field:

ts
html?: string;

The string is injected into the API-hosted iframe's popup layer when that entity is selected. Supply it via one of three methods:

MethodWhen to use
setEntityData(entities)Bulk-set HTML for many entities at once
setEntityDataById(id, entity)Update a single entity by ID
setEntityDefaults(defaults)Provide a fallback template applied to every entity that has no per-entity override

All three accept the same MapEntity shape. The html field is optional; omitting it on a given entity leaves the built-in popup in place for that entity.

Supplying custom HTML per entity

CDN

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });

  // Override the popup for entity 42 in building 7.
  await mapsted.maps.setEntityDataById(42, {
    id: 42,
    buildingId: 7,
    html: '<div class="my-popup"><h3>Coffee Shop</h3><p>Open 8 am – 8 pm</p></div>',
  });
</script>

npm

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

await maps.init({
  element: '#map',
  propertyId: 1234,
});

// Override the popup for entity 42 in building 7.
await maps.setEntityDataById(42, {
  id: 42,
  buildingId: 7,
  html: '<div class="my-popup"><h3>Coffee Shop</h3><p>Open 8 am – 8 pm</p></div>',
});

setEntityDataById validates both the id and entity parameters and throws MAPSTED-1061 if entity is not a plain object

Applying a fallback template to all entities

Use setEntityDefaults to set a single MapEntity object whose fields (including html) are applied to every entity that has no per-entity override. This is the closest equivalent to a global popup template.

CDN

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });

  await mapsted.maps.setEntityDefaults({
    id: 0, // id field is required by MapEntity; use 0 for the defaults object
    html: '<div class="my-popup"><p>No additional info available.</p></div>',
  });
</script>

npm

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

await maps.init({
  element: '#map',
  propertyId: 1234,
});

await maps.setEntityDefaults({
  id: 0,
  html: '<div class="my-popup"><p>No additional info available.</p></div>',
});

setEntityDefaults validates that defaults is a plain MapEntity object and throws MAPSTED-1061 otherwise

Bulk-setting HTML for multiple entities

setEntityData accepts an array of MapEntity objects. Supply the html field on any entry to override its popup.

CDN

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });

  await mapsted.maps.setEntityData([
    {
      id: 42,
      buildingId: 7,
      html: '<div class="my-popup"><h3>Coffee Shop</h3></div>',
    },
    {
      id: 87,
      buildingId: 7,
      html: '<div class="my-popup"><h3>Bookstore</h3></div>',
    },
  ]);
</script>

npm

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

await maps.init({
  element: '#map',
  propertyId: 1234,
});

await maps.setEntityData([
  { id: 42, buildingId: 7, html: '<div class="my-popup"><h3>Coffee Shop</h3></div>' },
  { id: 87, buildingId: 7, html: '<div class="my-popup"><h3>Bookstore</h3></div>' },
]);

setEntityData throws MAPSTED-1013 if the argument is not an array

Programmatically opening a popup

Use showPopup(entityId) to open the popup for a specific entity without requiring a user tap and without moving the camera or switching floors. This is the primary API for programmatic popup triggering.

CDN

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });

  // Open the default popup for entity 42.
  await mapsted.maps.showPopup(42);

  // Open the popup with a custom HTML override for this call.
  await mapsted.maps.showPopup(42, {
    html: '<div class="my-popup"><h3>Coffee Shop</h3><p>Open 8 am – 8 pm</p></div>',
  });
</script>

npm

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

await maps.init({
  element: '#map',
  propertyId: 1234,
});

// Open the default popup for entity 42 (camera stays put, floor unchanged).
await maps.showPopup(42);

// Provide inline HTML — equivalent to setEntityDataById + selectEntity in one round-trip.
await maps.showPopup(42, {
  html: '<div class="my-popup"><h3>Coffee Shop</h3><p>Open 8 am – 8 pm</p></div>',
});

showPopup throws:

Error codeCondition
MAPSTED-1090API is not yet in READY state
MAPSTED-1012entityId is null or undefined
MAPSTED-1013entityId is not a string or number

Tip: To open a popup and pan to the entity, call selectEntity(entityId) instead. showPopup is for cases where you want the popup to appear without disturbing the user's current map view.

Reacting to entity selection

Two events fire when an entity is selected. Both are typed in KnownEventPayload with an EntityData payload ({ buildingId, floorId, entityId }):

EventFires
selectWhen any entity is selected on the map
detailsViewWhen the details popup is opened for an entity

CDN

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });

  mapsted.maps.on('detailsView', ({ entityId, buildingId, floorId }) => {
    console.log('Details opened for entity', entityId, 'in building', buildingId);
    // Render your own sidebar or panel here using entityId.
  });
</script>

npm

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

await maps.init({
  element: '#map',
  propertyId: 1234,
});

maps.on('detailsView', ({ entityId, buildingId, floorId }) => {
  console.log('Details opened for entity', entityId, 'in building', buildingId);
});

Disabling the built-in popup entirely

To suppress the default popup without providing per-entity HTML — for example when you render a custom sidebar — set the defaultPopup feature flag to false. defaultPopup is defined in FeatureFlagSet:

CDN

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });

  await mapsted.maps.setFeatureFlags({ defaultPopup: false });

  mapsted.maps.on('select', ({ entityId, buildingId, floorId }) => {
    renderMySidebar({ entityId, buildingId, floorId }); // your own UI
  });
</script>

npm

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

await maps.init({
  element: '#map',
  propertyId: 1234,
});

await maps.setFeatureFlags({ defaultPopup: false });

maps.on('select', ({ entityId, buildingId, floorId }) => {
  renderMySidebar({ entityId, buildingId, floorId });
});

See the feature flags guide for the full setFeatureFlags reference.

Current public-API scope note

data-mapsted-trigger / data-mapsted-event / data-mapsted-payload inline attributes are NOT part of the public JS API surface. These attributes are an internal escape-hatch mechanism processed inside the map iframe, not by the JS API layer. They are treated as CMS-controlled and untrusted. Consumer code must not rely on these attributes firing events on the JS API emitter — there is no popupAction event in KNOWN_EVENTS.

To react to user interactions inside an html popup, attach DOM event listeners to elements rendered in your own external UI (sidebar, modal), or use maps.on('select', …) / maps.on('detailsView', …) to detect entity selection and build your own interaction surface outside the iframe.

No built-in popup-button callback: The API provides no mechanism for popup buttons inside the html string to call back into the host page without custom DOM event handling. If data-mapsted-trigger / data-mapsted-event callback support is needed (a named event fired on the maps emitter when a data-mapsted-trigger element is clicked), contact info@mapsted.com to request this as a future addition — it does not exist today.