StudioNope Themes Get the module →
HubSpot CMS Module

Store Locator Pro

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.

Get the module See it live ↓
Demo 1

Street map, list beside it

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.

Where to find us

Find a store near you

Search by town or postcode, or use your own location to sort the list by distance.

Demo 2

Google Maps, driven by your own key

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.

Our network

Every branch, on one map

Zoom in and the grouped markers open out into individual branches.

Demo 3

A street map of Romania, styled a long way from the default

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.

Magazinele noastre

Găsește un magazin

Caută după oraș sau folosește locația ta pentru a sorta lista după distanță.

  • Magazin

    Strada Lipscani 42
    București 030033

    Intrare din pasaj

    Program
    Luni – Sâmbătă, 10:00 – 20:00
  • Showroom

    Calea Floreasca 175
    București 014459

    Program
    Luni – Vineri, 09:00 – 19:00
  • Magazin

    Piața Unirii 12
    Cluj-Napoca 400098

    Program
    Luni – Sâmbătă, 10:00 – 20:00
  • Magazin

    Piața Victoriei 4
    Timișoara 300030

    Program
    Luni – Sâmbătă, 10:00 – 19:00
  • Magazin

    Strada Republicii 28
    Brașov 500030

    Program
    Luni – Sâmbătă, 10:00 – 19:00
  • Punct de ridicare

    Bulevardul Elisabeta 15
    Constanța 900711

    Program
    Zilnic, 09:00 – 21:00
  • Punct de ridicare

    Piața Mare 9
    Sibiu 550163

    Program
    Luni – Sâmbătă, 10:00 – 19:00
  • Punct de ridicare

    Strada Alexandru Ioan Cuza 6
    Craiova 200585

    Program
    Luni – Vineri, 10:00 – 19:00
  • Magazin

    Strada Republicii 20
    Oradea 410157

    Program
    Luni – Sâmbătă, 10:00 – 19:00
Demo 4

Map over the list, held in view while the list moves

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.

Service network

Where our engineers are based

Pick a category, or share your location to see the nearest team first.

Demo 5

List on its own, three across, dark

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.

Directory

Pick-up points across Europe

What it does

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.

The two map modes

Google Maps

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.

Street map

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.

Distance and near me

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.

Looking up a place name

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.

List and map together

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.

The map stays where it can be seen

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.

Directions

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.

Grouping markers

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.

Layouts

LayoutWhat it gives you
List left, map rightThe usual locator. The list scrolls in its own box while the map stays put.
Map left, list rightThe same, mirrored.
List above the mapOne column. Good for a short list.
Map above the listOne column, map first.
Map onlyThe map with its search controls and no cards.
List onlyA 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.

How many locations

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.

Wording

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.

Accessibility

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.

Reduced motion

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.

Style

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.

Troubleshooting

Notes on this page

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.

Demo 6

Six counters in one region, markers ungrouped

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.

Randstad

Six counters, one corner

The map opened on them, not on the whole country.

  • Staffed counter

    Elandsgracht 32
    1016 TW Amsterdam

    Hours
    Mon to Fri 8:00 - 20:00
  • Staffed counter

    Grote Houtstraat 41
    2011 SE Haarlem

    Hours
    Mon to Sat 9:00 - 19:00
  • Locker

    Breestraat 66
    2311 CS Leiden

    Hours
    Every day 7:00 - 22:00
  • Locker

    Grote Marktstraat 12
    2511 BJ Den Haag

    Hours
    Every day 6:00 - 23:00
  • Staffed counter

    Witte de Withstraat 25
    3012 BL Rotterdam

    Hours
    Mon to Sat 8:00 - 20:00
  • Staffed counter

    Oudegracht 158
    3511 AZ Utrecht

    Hours
    Mon to Fri 7:30 - 19:30