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
remoteQueryParamstofeatureRenderer, 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) — CSStopoffset 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 forfiltersand will be removed in a future release. Update your init call to usefilters.- Pre-seeding
data-shadow-embed-*-valueattributes on the container is no longer required —init({ filters, orderBy })handles seeding internally. - Reaching into
container.shadowRootto drive the order-by dropdown is no longer required — callmap.setOrderBy()instead. init({ sort })andsetSort()were renamed toinit({ orderBy })andsetOrderBy()to align with the rest of the API. No backwards-compatible alias is provided.