In this Astro JS location map post, we see how you can use the Leaflet library together with SvelteKit to add interactive location maps to your Astro sites. Astro builds fast static sites making it a great choice for brochure sites. These are where you have a basic site with home page, about, some product details and a contact page. Using the code in this tutorial you can improve the user experience (UX) on the map you might add to a contact page. This will let visitors, zoom in and out as well as pan to work out directions or find nearest public transport connections.
Leaflet is library for adding interactive maps. Basically with just latitude and longitude coordinates, you can add a custom map for any location with Leaflet. The maps are responsive and let you pinch and zoom on mobile as well as pan to see the vicinity on the map. Leaflet can work independently of a framework, though we will use Svelte here. This will make it easier to control how the map loads using Astro later. If that all sounds exciting, then why don’t we make a start?
We will build a basic map, like one you might find on a contact page. The maps we use wil be
sourced from OpenStreetMap
The map will show a location, with a marker. On top we will add some custom text to the marker. This will appear when the user hovers over it.
Let’s start by spinning up a fresh project. From the Terminal type the following commands:
When prompted choose Empty project, Yes to install pnpm dependencies. I opted for
Strict (recommended)TypeScript, so just delete any type annotations (in the code blocks
pnpm add astro add svelte command, accept the config changes proposed, and also to install the Svelte package. Apart from
those options, chose what makes most sense for you.
We need to add a couple more packages to get up and running with Leaflet:
That’s all the setup. The Terminal output should give you a URL for the dev server
http://localhost:3000/). Copy that into your
browser and you will see the skeleton template page.
As a last piece of setup, we will add an import alias to
tsconfig.json. These lets us write import statements like
import Component from '../../../Component.tsx' as
import Component from '~components/Component.tsx':
Ok, we’ll start by creating a Map component in Svelte. Create a
src/components folder and in there, add a
Map.svelte file with the following content:
This will essentially be a shell for the Map component, rendering it to a
figure HTML element. We will add the Leaflet logic in a Svelte action (coming soon). In
fact the code in line
2 imports that action for us. Note the script
tag in line
1 includes the attribute
export let syntax to declare inputs. Here we expect a location as an object composed on latitude and longitude
fields and an optional zoom factor. This is optional because we specify a default value of
19. Finally, we import some HTML markup (
markerMarkup), which the
action place on the marker label for us.
Actions are a way to access the component lifecycle. We see more on Svelte actions in the tutorial
on creating a Svelte video blog
use:setMap attribute on the
figure tag in line
14. This is exactly where we use the action.
Let’s define it next.
We will now add the code for the action. This is where we link in Leaflet, Mapbox and
OpenStreetMap. Create a
src/shared/actions directory and in there add
map.js) file with
This is mostly just boilerplate code to link in the Leaflet package. You will see the function we
define has two arguments while we only used one in the
That is because Svelte automatically sets the first argument to the node or element itself. Notice
we are able to pass in multiple parameter values, using an object for the second argument.
We use a dynamic import for the leaflet objects (lines
16). Typically this is not necessary. We
do it here specifically because importing the leaflet library causes Vite to evaluate the
window object. Although this is fine and dandy when code runs in the browser. Before that, Vite runs the
code in Server Side Render (SSR) mode and on the server, that
window object is undefined. As an aside, because we are using an action (which is only called on a mounted
element), we do not need a check within the function body that the code is running in the browser (and
not on the server).
28, we reference a Mapbox API key. We’ll set that up
You will need a Mapbox account for this part. On the free tier, you can have up to 50,000 montly loads
Once you have set up your account and logged in, select Tokens from the links at the top of the page then click + Create a token. You can call it whatever you like, you only need the actual public key value for this project. Copy this down or save it to a safe place.
Finally for this section create a
.env file in the root folder of your
project and paste in the content below (adding your new API key instead of the placeholder):
If you are using TypeScript, you might also want to edit
src/.env.d.ts in the project:
That’s all set up now. We should be able to read the key in line
28 of the action file just fine now!
To see this map, we just need to replace the content in our
src/pages/index.astro, add some styling and a touch more config. We’re on the home straight now. Replace the
src/pages/index.astro content with this:
This will not work yet, but let’s see what we have so far. In line
23, we use the Map component which we defined earlier. Most important in this line is the
client:load, the map would not load. If the map was going to appear far down the page, you might opt for
client:visible instead. In that case, Astro will instruct the browser only to load it when the user is about to
scroll it into view.
The map coordinates are set in line
7. Feel free to change these
to a location near you. To get coordinates, go to OpenStreetMap
We are using the new Google font Roboto Serif. Create a
folder then add fontface CSS in
src/styles/fonts.css — click to expand code.
We link to fonts in
/fonts here. This is a location which will be available
on the built site. We make a
public/fonts folder in our project for
this to work. Download these fonts from google-webfonts-helper
.woff2 files to the new
public/fonts folder. We take a more detailed look at self-hosting fonts with Astro in a separate video post.
Finally create the global CSS stylesheet file (
src/styles/global.css) and paste in this content:
src/styles/global.css — click to expand code.
src/pages/index.astro, we include the Leaflet CSS stylesheet so this will get bundled.
The site should all be working now. Finally, you can take a look in your browser!
Notice the blue marker shows up at the centre of the map. Let’s build the site now:
The page is small so it will literally take a few seconds to build. If you go back to your browser now, you will notice the marker has disappeared, you just see an outline. Try inspecting the outline.
Basically Vite did not know we needed it to bundle the PNG file for the marker. Do not worry
though, we can fix this. The way to ensure Vite bundles something is to import it and use it in
the code. We will import the PNG files from the Leaflet package. Then we will use a Leaflet
interface for defining custom icons. Instead of defining a custom marker icon though, we will link
to the default ones we import. Here we go — update
You can read more about using custom icons with Leaflet in the docs
pnpm dev. If all is well, rebuild. You should see the markers in all their glory now!
We have taken a look at adding a Astro JS Location maps in this post. In particular, we saw:
- how to use Svelte action with Astro,
- a trick for making sure Vite bundles assets at build time,
- how to set up Leaflet with Mapbox and OpenStreetMap.
Leaflet is highly customisable and I recommend checking their docs to explore other possibilities.
As a challenge, you might consider adding extra pins to the map, for example show the nearest
public transport terminals. Take a look at the full project code on the Rodney Lab GitHub page
- Leaflet is a fantastic map library which lets you add interactive maps to your projects. We saw it is possible to combine Leaflet with OpenStreetMap as well as Mapbox. We can do this with a Svelte map component in our Astro project. That component can contain a `figure` element which we can render the map to. We use a Svelte action to perform the Leaflet setup. Vite calls this code when the map component mounts.
- Yes, Svelte features like actions, stores and use directives are not just limited to SvelteKit. They work in Astro just fine. To use Svelte in Astro, just run `pnpm astro add svelte` in the Terminal. The tool will even offer to update your Astro config and install the Svelte package for you. You might also want manually to add the typescript as a peer dependency using the command `pnpm add --save-peer typescript`.
Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.
Finally, feel free to share the post on your social media accounts for all your followers who will
find it useful. As well as leaving a comment below, you can get in touch via @askRodney