24 Rivington Street
London EC2A 3DU
Bike parking at the rear
A searchable network of locations for HubSpot, on a real map. Google Maps with your own key, or a street map with a full-colour basemap that draws without one. The locations, the search, the distance sorting, the marker grouping and the list-to-map sync are the same on both.
A real slippy map out of the box, in the basemap's own colours. Leaflet is bundled inside the module, so no CDN is involved, and the basemap is a field with colour presets in it. Drag it, zoom it, and watch markers that sit on top of each other collapse into a count. Hover a card and its marker lifts. Click a marker and its card scrolls into view; click a card and the map goes to that branch and opens it. This instance is the module exactly as it arrives — no colour, corner or typeface has been touched.
The same locator drawn on Google Maps. Markers, grouping, the info window and the list-to-map sync are the module's own — one set of behaviour rendered on whichever map you pick. It lands in Google's own colours, and a field switches that to greyscale or to the colour fields on the Style tab. Point it at a map ID instead and Google's cloud styling is used. It needs a Google Cloud project with billing switched on and an API key. This instance has no key set, so what you are looking at is the fallback: the street map, drawn instead. A published page always shows a map.
A real street map, framed on ten Romanian shops, with the streets and place names a visitor needs to actually find one. Nothing in this instance shares a colour, a corner or a typeface with the one above it, and no CSS on this page touches the module — every one of those is an editor field. Click a card and the map goes to that shop and opens its details; click a marker and the card scrolls into view and takes focus.
A different basemap, a different arrangement and a different set of locations. When the map sits over the list it keeps its place at the top of the screen while the cards move under it, so a card further down still opens on a map the visitor can see. That is a field, with the gap above it and the height it takes on a phone. The basemap is a field too, and this one is OpenStreetMap standard rather than the CARTO basemap above. Distances read in miles here.
No map at all. The same locations become a filterable directory in as many columns as you set. Search and the category filter still work, and each card keeps its directions link — a plain URL with the coordinates in it, so it needs no account anywhere. Every colour here is a field turned dark, including the dropdown, which is the module's own listbox rather than the operating system's.
Store Locator Pro puts a searchable network of locations on a HubSpot page. Locations are a repeater, so an editor adds, removes and reorders them without touching a template. Every one carries a name, an address, coordinates, a phone number, an email address, opening hours, a category, a photograph, a link and a short note.
Search, category filtering, distance sorting and the radius limit all run in the visitor's browser against data already on the page. None of it calls a service.
Driven by your own Google Cloud key. Create a project, switch billing on, enable Maps JavaScript API, create a key and restrict it to your own domains before you paste it in — the key is readable by anyone who views the page. Google publishes a monthly free allowance and bills per map load above it. Without a key the map area says so and draws nothing.
The map is styled from the colour fields, so it lands greyscale rather than in Google's blue and orange. Put a map ID in instead and Google's cloud styling for that map ID is used and the colour fields stop applying. Markers, grouping, the info bubble and the list-to-map sync are the module's own, drawn on Google's panes, so a pin looks the same whichever map is underneath it.
The script loads once per page however many instances are on it. Two instances with different keys on one page: the first to load wins.
Leaflet, bundled inside the module's own JavaScript file. Nothing is fetched from a CDN. It loads once per page however many instances are on it, and a CDN outage cannot take your map with it.
The tile field ships with CARTO's light basemap so a map draws straight away. CARTO's terms cover low volume and non-commercial use — read them, and for a commercial site paste in the address from whichever provider you hold an account with. MapTiler, CARTO, Stadia and Thunderforest all have a free tier and none asks for a card to start. It looks like this:
https://api.maptiler.com/maps/basic-v2/{z}/{x}/{y}.png?key=YOUR_KEY
The OpenStreetMap Foundation's own tile servers are deliberately not the default. Their usage policy states that access may be withdrawn from any commercial use at any time, and a default that can be withdrawn would blank the map on every site running it.
Every tile provider requires a credit line. The attribution field carries it, and it appears in the corner of the map.
The near-me button asks the browser for the visitor's position through the standard Geolocation API. That is a browser permission prompt — nothing is sent anywhere. The distance from that point to each location is worked out with the haversine formula against the stored coordinates, the list is reordered nearest first, and a radius picker appears. Radius options and the unit are fields.
Sorting reorders the cards in the page, so the nearest one is genuinely first.
There is one optional lookup and it is off out of the box. Switched on, pressing Enter in the search box sends that single term to the OpenStreetMap Nominatim service to turn it into coordinates, which then acts as the starting point for distance sorting. It never fires while someone types, and it is held to one request a second, which is what the Nominatim usage policy asks for. Their policy also asks for a contact address, and there is a field for it.
With the switch off, the search box is plain text matching over the location name, town, region, postcode, country, address and category. Nothing leaves the page.
Hover a card and its pin lifts. Click a location name and the map flies to it, goes in to street level and opens its bubble, so the visitor sees the door rather than a dot in a county. The level is a field, and it is a floor: someone already closer in keeps the view they chose. The flight has a duration field, and anyone who has asked their device for less motion gets the same arrival without it. Click a pin and the matching card scrolls into view, becomes active and takes focus. The location name is a real button, so all of this works from the keyboard, and the links inside the card stay ordinary links.
When the map sits over the list, it holds its place at the top of the screen while the cards move under it. Without that, clicking a card near the bottom of a long list does something off screen. It is a field, with the gap above it, and it applies on a phone to every layout, where the height it takes comes from the small-screen map height so it never eats the whole display.
Each card can carry a directions link that opens in Google Maps, Apple Maps, Waze or OpenStreetMap. These are plain URLs with the coordinates in them and no key of any kind:
https://www.google.com/maps/dir/?api=1&destination=51.5261,-0.0800
https://maps.apple.com/?daddr=51.5261,-0.0800
https://www.waze.com/ul?ll=51.5261,-0.0800&navigate=yes
They are written into the page on the server, so they work with scripting switched off. The whole feature can be turned off.
On a street map, markers that land within a set number of pixels of each other collapse into one marker showing how many are inside it. Click it and the map frames that group. The grouping distance is a field, and grouping can be switched off. It is worked out inside the module, so nothing extra is loaded.
| Layout | What it gives you |
|---|---|
| List left, map right | The usual locator. The list scrolls in its own box while the map stays put. |
| Map left, list right | The same, mirrored. |
| List above the map | One column. Good for a short list. |
| Map above the list | One column, map first. |
| Map only | The map with its search controls and no cards. |
| List only | A filterable directory in as many columns as you set. |
On small screens every layout becomes a single column, and whether the map or the list comes first is a field. The list stops being its own scroll box there, because a scroller inside the page scroll is unusable on a touch screen.
Around a hundred is the comfortable ceiling. Every location is real markup on the page, and filtering walks all of them on each keystroke. That is fast at this size and it keeps the whole thing free of a back end. If your network is larger than that, this is not the right shape for it.
Every string a visitor can read is a field: the search placeholder, the button text, the result count templates, the empty state, the no-results state, the labels on phone, email, hours and directions, and the descriptions read out to screen readers. Result counts are templates with {count}, {radius} and {unit} in them, so they translate without a developer.
The location name is a button with a pressed state, so the list can be driven from the keyboard. Pins are buttons with their own labels. The result count is a live region, so a screen reader hears the list change as filters are applied. Focus rings are visible and their colour and width are fields. The town, region, postcode and country are searchable even on a card that does not print them, and they are hidden from the accessibility tree so nothing is read twice.
A visitor whose system asks for less motion gets no lift on the pins, no eased transitions, no animated scrolling to a card and no animated panning on the street map. That follows the reader's own setting, so an editor cannot switch it off by accident.
Every colour, size, weight, letter spacing, radius and space is a field on the Style tab, grouped by what it affects: typography, key colours, section, container, heading, search controls, location cards, card text, map, marker groups, map bubble, and the empty and no-result states. Colour fields carry opacity as well as a colour and both are used. Body and heading fonts and the accent colour inherit from your HubSpot theme settings until you say otherwise. There are no hard-coded colours, sizes, fonts or strings in the module.
{z}, {x} and {y} and see what comes back.Six instances of the same module. They differ by which map they draw on, by layout and by content. The first instance is the module exactly as it arrives. Two others are styled a long way from it — a warm palette with a serif heading, and a dark directory — because every colour, corner, typeface and space is an editor field and the only way to show that is to move them. Every map here is a real map with real streets on it. No CSS on this page touches the module.
Six counters across one region, with marker grouping switched off so every one stands on its own. The map frames itself on them, so it opens on the region rather than on the whole country. Grouping, the grouping distance, the zoom limits and what the map opens on are all fields.