Early Adopter — 50% off. Ends May 31
Embedding

Widget.js Reference

Use the JavaScript widget for embedding maps with Shadow DOM.

Widget.js Reference

The Mapsemble widget is a lightweight JavaScript file that embeds a fully interactive map into any web page. It uses Shadow DOM so the map is isolated from the host page's styles and scripts.

There are two ways to use it: automatic setup (drop in a <div>, done) and programmatic setup via Mapsemble.init() (needed if you want to drive filters, ordering, or custom card rendering from your own JavaScript).

Automatic setup

Add the script tag and one container element per map:

<script src="https://app.mapsemble.com/widget.js"></script>
<div data-mapsemble-map="YOUR_MAP_ID"></div>

That's it. The widget scans for elements with data-mapsemble-map and renders a map in each. Each map is independent.

Programmatic setup — Mapsemble.init(options)

When you need to pass filters, an order-by, a custom card renderer, or to keep a handle for later updates, call Mapsemble.init() yourself:

const map = Mapsemble.init({
  container: '#my-map',      // CSS selector or HTMLElement
  mapId: 'YOUR_MAP_ID',
  embed: 'shadow',
  language: 'en',
  mode: 'light',
  filters: { category: 'hotel' },
  orderBy: 'price-asc',
});

// Later, update the map in response to user input:
map.setFilters({ category: 'hotel', price_max: '200' });
map.setOrderBy('rating-desc');

init() returns an instance object with methods bound to that specific map. On a page with multiple maps, call init() once per map and keep each handle — the instance methods always target the right one.

init() options

Option Type Description
container CSS selector or HTMLElement Required. The element the map will render into.
mapId string Required. The map's UUID in Mapsemble.
embed 'shadow' Embed mode. Default 'shadow' — renders into a shadow root and supports featureRenderer.
filters object Initial filter values. Seeded before the widget's first feature fetch, so the map loads already filtered. See Filters below.
orderBy string Initial order-by slug (e.g. 'price-asc', 'rating-desc'). Applied before the first feature fetch.
language string BCP-47 locale. Default 'en'.
mode 'light' | 'dark' Color mode. Default 'light'.
translations object Map of English phrase → localized phrase, applied to all widget text.
onlyZones string[] Render only these zones (e.g. ['primary-filters', 'map']). Useful for split embeds.
excludeZones string[] Hide these zones from an otherwise default layout.
searchUrl string Destination for the search button in filter-only embeds.
minHeight number | string Sets min-height on the container. Number → pixels; string → any CSS length.
preventScale boolean On mobile, injects user-scalable=no into the viewport meta.
scrollCapture boolean See Scroll capture.
scrollCaptureTop number | string Top offset for scrollCapture. Default '0px'.
featureRenderer function Custom renderer for feature cards and popups. See Custom card rendering.
featureUnmount function Cleanup callback paired with featureRenderer.
onCount function Callback fired with the total feature count after each load.
countPhrase function Customize the count text shown inside the widget.

queryParams is accepted as a deprecated alias for filters — it logs a console warning. Migrate to filters.

Instance methods

Each call to Mapsemble.init() returns an object with methods bound to that map.

map.setFilters(filters)

Replace the active filter set. The map immediately refetches features from the datasource with the new filters.

// Apply filters
map.setFilters({
  category: 'restaurant',
  price_max: '50',
});

// Clear all filters
map.setFilters({});

Key behavior:

  • Full replace — each call overwrites the previous filter set. To keep a filter, include it every call.
  • Immediate refetch — the map reloads as soon as filters change.
  • Merged with built-in filters — if the map has its own filter UI configured, both sets combine. Use distinct keys to avoid collisions.
  • Arbitrary keys — the object is passed through to your datasource endpoint. Your endpoint decides how to interpret it.
  • Forwarded to card renderers — the same values are passed as remoteQueryParams to featureRenderer, so custom cards can reflect the active filters.

map.setOrderBy(orderBy)

Change the active order-by. Drives the built-in order-by dropdown when it's visible and triggers a feature reload.

map.setOrderBy('price-desc');
map.setOrderBy(null);        // clear (equivalent to 'default')

map.setVisibleIds(ids, options)

Show only the given feature IDs. Empty array shows all.

map.setVisibleIds(['feature-1', 'feature-2']);
map.setVisibleIds([], { orderBy: 'price-asc' });

map.setMainIds(ids)

Mark the given features as "main" (full-size markers with labels); everything else is dimmed. Client-side only — no reload triggered.

map.setMainIds(['feature-1', 'feature-2']);

map.setHoverId(id)

Highlight a single marker (e.g. when the user hovers a related list item). Pass null to clear.

map.setHoverId('feature-1');
map.setHoverId(null);

map.setTranslations(translations)

Merge additional translations into the widget. Existing translations are preserved.

map.setTranslations({ 'Show results': 'Ergebnisse anzeigen' });

map.destroy()

Tear the widget down and remove it from the container. Call this only if you're rebuilding the map from scratch — regular updates should go through setFilters / setOrderBy.

Static shortcuts

For simple pages with exactly one instance of a given mapId, the static methods work directly with the map ID:

Mapsemble.setFilters('YOUR_MAP_ID', { category: 'hotel' });
Mapsemble.setOrderBy('YOUR_MAP_ID', 'price-asc');

Every instance method has a static counterpart (Mapsemble.setFilters, Mapsemble.setOrderBy, Mapsemble.setVisibleIds, Mapsemble.setMainIds, Mapsemble.setHoverId, Mapsemble.setTranslations). The first argument can be a map ID string, a container element, or an instance.

If more than one instance of a given map ID exists on the page, the static methods target the first match and log a warning. Prefer the instance API in that case.

Consumer integration guide

This walkthrough shows how to wire Mapsemble into an app that drives filters, pagination, and ordering from its own UI, and serves features from its own backend.

1. Point Mapsemble at your datasource

Configure the map's datasource URL in Mapsemble's admin to point at your endpoint. Mapsemble will issue GET requests for features, sending query parameters including:

Parameter Description
mapsemble[MAP_ID][extent] WKT POLYGON(...) bounding box
mapsemble[MAP_ID][filters] JSON-encoded filter object (your filters merged with built-in filters)
mapsemble[MAP_ID][orderBy] Current order-by slug
mapsemble[MAP_ID][remoteQueryParams] JSON-encoded copy of filters, exposed to custom card renderers
mapsemble[MAP_ID][offset], [limit] Pagination
mapsemble[MAP_ID][queryExtent] Set to 1 when a total bounding box is needed

Respond with a GeoJSON FeatureCollection:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "42",
      "geometry": { "type": "Point", "coordinates": [4.8952, 52.3702] },
      "properties": { "price": "€ 450", "rating": 8.5, "title": "..." }
    }
  ],
  "properties": { "total": 150 }
}

2. Initialize with your initial state

const map = Mapsemble.init({
  container: document.querySelector('#map'),
  mapId: 'YOUR_MAP_ID',
  embed: 'shadow',
  filters: readFiltersFromUrl(),
  orderBy: readOrderByFromUrl(),
});

Passing filters and orderBy to init() guarantees the very first feature fetch uses them. The widget seeds its internal state from these options before the first request fires.

3. Push filter changes from your UI

document.querySelector('#price-filter').addEventListener('change', (e) => {
  map.setFilters({
    ...currentFilters,
    price_max: e.target.value,
  });
});

Each setFilters call triggers one feature reload. Debounce if your UI emits changes rapidly.

4. Customize card rendering (optional)

If you want to render feature cards and popups with your own components, pass a featureRenderer:

Mapsemble.init({
  container: '#map',
  mapId: 'YOUR_MAP_ID',
  embed: 'shadow',
  featureRenderer: (el, feature, filters, location) => {
    // el is a slot inside a shadow root — your CSS needs to be injected here.
    injectStyleOnce(el.getRootNode(), '/your-app.css');

    el.innerHTML = `
      <article>
        <h3>${feature.properties.title}</h3>
        <p>${feature.properties.price}</p>
      </article>
    `;
  },
  featureUnmount: (el) => { /* tear down any listeners/frameworks */ },
});

The filters argument to featureRenderer is the widget's current filter state — use it so cards stay consistent with the map.

location is one of 'list', 'list_mobile', 'popup', 'popup_mobile'.

5. Two-way sync with the URL (optional)

Keep the map and your URL in sync so filters survive a reload:

window.addEventListener('popstate', () => {
  map.setFilters(readFiltersFromUrl());
  map.setOrderBy(readOrderByFromUrl());
});

Scroll capture

On mobile the widget can integrate with host-page scroll. When enabled, the widget becomes a sticky section — the user scrolls the host page, and once the card list is in view the scroll transfers to the internal card list. When the list reaches the end, the page resumes scrolling.

Mapsemble.init({
  container: '#my-map',
  mapId: 'YOUR_MAP_ID',
  embed: 'shadow',
  scrollCapture: true,
  scrollCaptureTop: '84px',
});
  • scrollCapture (boolean) — enable the sticky scroll-through behavior. Only active when container width < 768px.
  • scrollCaptureTop (string | number) — CSS top offset for the sticky widget. Default '0px'. Use to clear a fixed header.

Callbacks

onCount(total)

Fires after every feature load with the total matching count (accounting for filters and extent). Use it to update an element outside the widget:

Mapsemble.init({
  container: '#my-map',
  mapId: 'YOUR_MAP_ID',
  embed: 'shadow',
  onCount: (count) => {
    document.querySelector('#property-count').textContent = `${count} properties`;
  },
});

countPhrase(total)

Replace the count text rendered inside the widget. Return a string; it's shown verbatim.

Mapsemble.init({
  container: '#my-map',
  mapId: 'YOUR_MAP_ID',
  embed: 'shadow',
  countPhrase: (count) => {
    if (count === 0) return 'No results';
    if (count === 1) return '1 result';
    return `${count} results`;
  },
});

Migrating from older versions

  • Mapsemble.init({ queryParams }) is a deprecated alias for filters and will be removed in a future release. Update your init call to use filters.
  • Pre-seeding data-shadow-embed-*-value attributes on the container is no longer required — init({ filters, orderBy }) handles seeding internally.
  • Reaching into container.shadowRoot to drive the order-by dropdown is no longer required — call map.setOrderBy() instead.
  • init({ sort }) and setSort() were renamed to init({ orderBy }) and setOrderBy() to align with the rest of the API. No backwards-compatible alias is provided.