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

Google Maps, with a row of details on every card

A bookbinder with counters on four continents, drawn on the map data from Google with a key in the field. Ask it to sort by distance from you and it answers from wherever you are reading this, and the numbers on the cards and on the pins renumber together to follow the order shown. Each location carries its own list of short lines — parking, step-free access, click and collect — and each line can take an icon the editor picks from the HubSpot icon library. Some rows have an icon, some do not, and the text still starts on the same line. One card has no rows at all and closes up around it. Nothing on the Style tab has been changed here apart from the swatches the Google basemap is built from.

Marlow and Reid

Bookbinders and stationers

Counters city by city, from Lisbon to Tokyo. Search a town, or use your own location to sort them by distance.

  • Bindery

    2-8-4 Jimbocho
    Chiyoda City, Tokyo 101-0051

    • Repairs and rebinding, quoted in store
    • Three minutes from Jimbocho station
    • Step-free entrance from the arcade
    • Late until 20:00 on Fridays
    Open
    Mon to Sat, 10:00 - 19:00
  • Shop

    84 Charing Cross Road
    London WC2H 0AA

    First floor, above the arcade

    • Click and collect from 10:00
    • Lift from the street entrance
    • Sample books kept behind the counter
    Open
    Mon to Sat, 9:30 - 18:30
  • Bindery

    200 Gertrude Street
    Fitzroy VIC 3065

    • Box making and slipcases
    • Two hour parking on Gertrude Street
    • Dogs welcome
    Open
    Mon to Sat, 9:00 - 18:00
  • Shop

    Strada Lipscani 25
    Bucharest 030033

    • Coffee cart on the corner from 7:00
    • Card only
    • Click and collect
    Open
    Tue to Sat, 10:00 - 18:00
  • Shop

    126 Crosby Street
    New York NY 10012

    • Gift wrapping at no charge
    • Step-free throughout
    • Wifi in the reading room
    Open
    Mon to Sat, 10:00 - 19:00
  • Collection counter

    Torstrasse 140
    10119 Berlin

    • Collection only, no counter service
    • Ring the bell on the left of the door
    Open
    Mon to Fri, 10:00 - 18:00
  • Shop

    72 Kloof Street
    Gardens, Cape Town 8001

    • Marbled paper cut to size while you wait
    • Bike racks outside the door
    Open
    Tue to Sat, 9:00 - 17:00
  • Bindery

    12 Rue de Seine
    75006 Paris

    • Hand sewing and leather work
    • Ramp at the courtyard door
    Open
    Tue to Sat, 11:00 - 19:00
  • Collection counter

    78 Neil Road
    Singapore 088839

    • Four minutes from Outram Park
    • Collection from the desk at the rear
    Open
    Mon to Sat, 11:00 - 20:00
  • Shop

    Rua Garrett 73
    1200-203 Lisbon

    Closed on market Saturdays until 14:00

    Open
    Fri to Sun, 10:00 - 18:00
  • Collection counter

    790 Queen Street West
    Toronto ON M6J 1G3

    • Click and collect until 19:00
    • Free parking after 17:30
    Open
    Mon to Sat, 10:00 - 18:00
  • Shop

    Calle Amsterdam 62
    Hipodromo, 06100 Mexico City

    • Reading room open to customers
    • Workshops on the last Sunday of the month
    Open
    Every day, 9:00 - 18:00
Demo 2

Google Maps, with a photograph on every card

A furniture and interiors company across Canada. The photograph is a field on each location, and where it sits on the card, its shape and its corners are fields too — here it runs the full width above the text, three cards across, with the map held over them while the list moves. The last card has no photograph and the layout closes up around it rather than leaving a hole. The indigo, the eight pixel corners and the soft card shadow are field values on this instance.

SHOWROOMS

Find a showroom near you

Twelve showrooms, design studios and warehouses across Canada.

  • Living room setting in the West Fourth showroom
    Showroom

    1830 West 4th Avenue
    Vancouver BC V6J 1M4

    Design consultations by appointment

    Open
    Mon to Sat, 10:00 - 19:00
  • Bedroom setting in the Gastown showroom
    Showroom

    320 Water Street
    Vancouver BC V6B 1B6

    Open
    Every day, 10:00 - 20:00
  • Bathroom setting in the Johnson Street studio
    Design studio

    560 Johnson Street
    Victoria BC V8W 3C6

    Open
    Mon to Sat, 10:00 - 18:00
  • Dining setting in the Kensington showroom
    Showroom

    1219 Kensington Road NW
    Calgary AB T2N 3P4

    Open
    Mon to Sat, 9:30 - 18:00
  • Bedroom setting in the Banff Avenue studio
    Design studio

    215 Banff Avenue
    Banff AB T1L 1B7

    Fabric library on the first floor

    Open
    Every day, 8:00 - 21:00
  • Bathroom setting in the Whyte Avenue showroom
    Showroom

    10442 Whyte Avenue NW
    Edmonton AB T6E 2A3

    Open
    Mon to Sat, 10:00 - 19:00
  • Kitchen setting at the Albert Street warehouse
    Warehouse

    91 Albert Street
    Winnipeg MB R3B 1G5

    Open
    Mon to Fri, 10:00 - 18:00
  • Living room setting in the Queen West showroom
    Showroom

    774 Queen Street West
    Toronto ON M6J 1G1

    Open
    Every day, 10:00 - 20:00
  • Seating setting in the ByWard Market studio
    Design studio

    55 ByWard Market Square
    Ottawa ON K1N 9C3

    Open
    Mon to Sat, 10:00 - 18:00
  • Living room setting in the Saint-Denis showroom
    Showroom

    4200 Rue Saint-Denis
    Montreal QC H2J 2K9

    Open
    Mon to Sat, 10:00 - 19:00
  • Storage setting at the Barrington Street warehouse
    Warehouse

    1541 Barrington Street
    Halifax NS B3J 1Z5

    Open
    Mon to Sat, 10:00 - 18:00
  • Warehouse

    200 Water Street
    St John's NL A1C 1A9

    Open
    Tue to Sat, 10:00 - 17:30
Demo 3

No key at all, on the bundled street map

A bakery across Ireland. There is no Google key on this instance and none is needed: Leaflet ships inside the module and the basemap is a field with presets in it. Plain cards here — no icon rows, no photographs. The light grey ground, the large light heading, the borderless cards on a soft shadow and the blue are field values, which is the point: none of the three instances on this page has a line of CSS behind it.

Ardmore Bakehouse

Where to find us

Search a town, or let the browser sort the list by how far away each one is.

  • Bakehouse

    21 South William Street
    Dublin 2

    Open
    Mon to Sat, 7:30 - 18:00
  • Bakehouse

    6 Wexford Street
    Dublin 2

    Open
    Mon to Sat, 7:30 - 18:00
  • Cafe

    12 Upper George's Street
    Dun Laoghaire, Co. Dublin

    Open
    Every day, 8:00 - 17:00
  • Bakehouse

    30 Catherine Street
    Limerick

    Open
    Mon to Sat, 8:00 - 17:00
  • Counter

    5 High Street
    Kilkenny

    Open
    Tue to Sat, 8:30 - 16:30
  • Counter

    22 John Roberts Square
    Waterford

    Open
    Mon to Sat, 8:00 - 17:00
  • Cafe

    18 High Street
    Killarney, Co. Kerry

    Open
    Every day, 8:00 - 18:00
  • Market stall

    4 Bridge Street
    Westport, Co. Mayo

    Open
    Wed to Sun, 8:30 - 16:30
Demo 4

The map on its own, with the search above it

A charging network across the Netherlands and Belgium on the map-only layout. There are no cards here: the search box, the category filter, the near-me button and the radius picker sit above a map that fills the section, and every answer is read off the pins and their bubbles. Search a town and the pins thin out. Ask for the nearest and the picker appears with the distances applied. Click a pin and the map travels to it over the time set on the field and opens the address. This is also the instance with the place-name lookup switched on, so pressing Enter in the search box turns a town into a starting point and the radius picker appears with it. This one draws on the bundled street map with the full-colour basemap, so the layout is the only thing that changes between it and the instances above.

Voltway

Where you can charge

Search a town, or ask for the points nearest to you.

Press Enter to look up a town or postcode.

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 at console.cloud.google.com, switch billing on, enable Maps JavaScript API, create an API key, and restrict it to your own domains before you paste it in. The key is readable by anyone who views the page — its safety comes from that restriction. An unrestricted key can be lifted off your page and used on someone else's site, and the loads land on your bill.

Google's Dynamic Maps allowance covers 10,000 map loads a month at no cost, then $7.00 per 1,000 loads up to 100,000 a month. Billing has to be switched on for the project either way, allowance or not.

It lands in Google's own colours. A field greyscales it, another builds the map's palette out of the swatches on the Style tab, and a map ID hands the styling to your Google Cloud console and stops the colour fields applying. Whether Google draws the shops and landmarks it knows about is its own switch and it applies whichever way the colours are set, except under a map ID, where the cloud style decides. Markers, grouping, the info window 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.

Leave the key field empty with the mode still on Google Maps and the street map is drawn instead. A published page always shows a map, and demo 3 on this page is that street map with no key anywhere on the instance.

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 radius picker is built from the radius options, and the radius it starts on is a separate field. Set that field to a number the options do not hold and it is added to the picker where it belongs in the order, so the limit applies from the first render and the visitor can read what it is set to.

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 the map lands on it whichever side it was on before the click. The flight has a duration field, on the street map and on Google Maps alike, 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.

Detail rows on a card

Each location carries its own repeater of short lines. A row is a piece of text and, if you want one, an icon picked from HubSpot's icon library on the row itself. Use them for the things a visitor checks before setting off — parking, step-free access, click and collect, a late night.

Rows work with icons, without them and mixed. Where any row on a card carries an icon, the card keeps an icon column, so a row left without one starts its text on the same line as the rows above it. Where no row on a card has an icon, the column is gone and nothing is indented. A location with no rows renders no list and no gap. The icon size and colour, the gap to the text, the space between rows, the space above them and the text size and colour are all fields.

A photograph on a card

Each location takes a photograph. Whether photographs show at all is one switch; where the photograph sits — left of the text, right of it, or across the full width above it — its shape, its width and its corner radius are fields. A location left without one takes no space for it and the card closes up. With the numbering switch on, a card with no photograph shows its number in that place instead.

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. Search, category, near me and the radius picker all still apply, to the pins. Demo 4 on this page is that layout.
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.

The list keeps step with the map

In the two side-by-side layouts the list is capped so the two columns are the same height. The cap follows whatever height the map is actually at: the map height field, the smaller height it settles to while it is held at the top of the screen, and any height a visitor has dragged the handle to. Drag the map taller and the list gets the same room in the same movement, so the two edges stay level and the list's own scroll area grows with it. A field switches this to a height of your own, or to letting the list be as tall as its cards need.

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

The same module four times over, four businesses, four countries. Two draw on Google Maps with a key in the field; the other two have no key and draw the bundled street map. One of them is the map on its own with no cards beside it. One shows the icon detail rows, one shows a photograph on every card, and one has plain cards. The first is the render the module arrives with, black and white; the other two are moved a long way from it on colour, corner radius, shadow and weight. Every map here is a real map with real streets on it, and every address is a real one. No CSS on this page touches the module: every difference between them is a field value on the instance.