Use Mapbox GL JS in a Svelte app
Svelte is a popular JavaScript web framework used for increasing client performance. Since Svelte manipulates the DOM, it can be confusing to connect Svelte with other libraries that also manipulate the DOM and manage state — like Mapbox GL JS.
In this tutorial, you will learn how to create a Svelte web app that uses Mapbox GL JS to render a map, display the coordinates of the map center point and its zoom level, then update the display when a user interacts with the map. You will be able to use the principles discussed in this tutorial to create more complex apps that use both Svelte and Mapbox GL JS. This tutorial shows code for Svelte Bindings and Component Lifecycles.
Getting started
- A Mapbox access token. Your Mapbox access tokens are on the Access Tokens page of your Developer Console.
- Mapbox GL JS. Mapbox GL JS is a JavaScript library used for building web maps.
- A text editor. Use the text editor of your choice for writing HTML, CSS, and JavaScript.
- Git. You will need to be able to run
git
commands from your command line. - Node.js and npm. To run the commands necessary to run your Svelte app locally, install Node.js and npm.
- Working familiarity with Svelte. You don't need to have a lot of experience using Svelte to complete this tutorial, but you should be familiar with the underlying concepts and workflows.
Set up the Svelte app structure
To get started, clone Svelte's "template" GitHub repository. This will create a base layer to build any Svelte app upon. Wherever you want the folder for this project to exist on your computer, navigate to that directory via the command line and run the following command:
git clone https://github.com/sveltejs/template use-mapbox-gl-js-with-svelte
Then, in your command line, cd
into the new directory use-mapbox-gl-js-with-svelte
and run the following command:
npm install
This will install the dependencies that your app requires, creating the file package-lock.json
and the folder node_modules
.
You also need to install Mapbox GL JS in this project. In the same directory, run the following command:
npm install mapbox-gl
Finally, open the index.html
file in the public
folder in a text editor of your choice. Add the following CSS within the <head>
of the document to make sure your app will use all the space available in the browser window:
<style>
body {
margin: 0;
padding: 0;
}
</style>
Setup is complete and you should have the following file structure:
use-mapbox-gl-js-with-svelte
node_modules
public
favicon.ico
global.css
index.html
scripts
setupTypeScript.js
src
App.svelte
main.js
.gitignore
package-lock.json
package.json
README.md
rollup.config.js
Save your changes.
Create the Svelte app
All the programming in this tutorial, including HTML, CSS, and JavaScript will occur in the src/App.svelte
file. Open this file.
Set up the Svelte app
This app will include a Mapbox map, JavaScript to handle storing and updating information about the map, a <div>
to show that information, and CSS to style the <div>
. You should set up the bones of your app like this; we will handle the map itself later. Delete any HTML in App.svelte
and replace it with the following:
<head> </head>
<script></script>
<div></div>
<style></style>
Add Mapbox GL JS
Add the following import
statement between your <script>
tags to import the Map object from Mapbox GL to your Svelte app:
import { Map } from 'mapbox-gl';
Add the following immediately below the line above to give your app access to Mapbox GL JS's CSS properties:
import '@site/src/node_modules/mapbox-gl/dist/mapbox-gl.css';
Add variables
To load a map on a webpage with Svelte, we will need to create some context for the map. Specifically, we need variables for the map, the HTML element that will contain the map, and the map's starting position (including longitude, latitude, and zoom level).
Add the following between your <script>
tags, below your import
statement:
let map;
let mapContainer;
let lng, lat, zoom;
lng = -71.224518;
lat = 42.213995;
zoom = 9;
These positional values will create a map centered near Boston, Massachusetts.
Use Svelte binding
Let's study the mapContainer
variable for a moment. The Mapbox map
needs certain contextual attributes defined immediately to work, such as the map's center
and style
. One such attribute is the map's container
. This container is an <div>
that the map renders in.
To do this, we will use Svelte binding. Between your empty <div>
tags, insert the following:
<div class="map-wrap">
<div class="map" bind:this="{mapContainer}" />
</div>
This "binds" the variable mapContainer
to the <div>
with class "map". When the map is rendered on the page, this is where it will be.
Add map CSS
Now that there exists an HTML element with a class of map
, we can apply CSS styling to that class. Between your empty <style>
tags, add the following:
.map {
position: absolute;
width: 100%;
height: 100%;
}
Add Svelte lifecycle
You will import Svelte functions right below where you imported the Map
object from Mapbox GL. On the next line, add:
import { onMount, onDestroy } from 'svelte';
onMount
and onDestroy
are Svelte lifecycle functions. onMount
in particular runs after a component is first rendered to the DOM. The creation of the map should go in onMount
.
Take note of your Mapbox access token, then add the following directly underneath your variable declarations and definitions:
onMount(() => {
const initialState = { lng: lng, lat: lat, zoom: zoom };
map = new Map({
container: mapContainer,
accessToken:YOUR_MAPBOX_ACCESS_TOKEN,
style: `mapbox://styles/mapbox/outdoors-v11`,
center: [initialState.lng, initialState.lat],
zoom: initialState.zoom
});
});
onDestroy(() => {
map.remove();
});
At this point, you've added enough code to load a Mapbox map in a Svelte app. Run npm run dev
in your app's root directory to launch the development server, and you should see an interactive map of Boston.
Save your changes.
Display map information in UI
This app will need to be able to store and render the longitude, latitude, and zoom for the map in a UI element. These values will all change as your user interacts with the map, and the UI will update with it.
Add UI HTML
We need variables to store this information, but these variables (lng
, lat
, and zoom
) are already created. It's time to add to the <div>
tags that will become the informational sidebar UI element. Add the following HTML between your root <div>
tags, above the <div>
with class "map-wrap">:
<div class="sidebar">
Longitude: {lng.toFixed(4)} | Latitude: {lat.toFixed(4)} | Zoom:
{zoom.toFixed(2)}
</div>
Add sidebar CSS
If you run npm run dev
at this point, you will see that the map's initial position and zoom are displayed above the map; The presentation is not styled and does not change when interacting with the map.
Before we work on updating the display with current data, we should style the display. Between your <style>
tags, under the rules for the map
class, add the following:
.sidebar {
background-color: rgb(35 55 75 / 90%);
color: #fff;
padding: 6px 12px;
font-family: monospace;
z-index: 1;
position: absolute;
top: 0;
left: 0;
margin: 12px;
border-radius: 4px;
}
Save your changes.
Update center and zoom information
Next, you need to create a function that stores the new latitude, longitude, and zoom that you get when a user interacts with the map. You will write Mapbox GL JS map.on()
functions that reset the value of these variables when a user moves the map.
Create that function under zoom = 9;
in your <script>
tags:
function updateData() {
zoom = map.getZoom();
lng = map.getCenter().lng;
lat = map.getCenter().lat;
}
At this point, this function is never called. You must apply a Mapbox GL JS map.on()
function with a 'move'
event. In onMount()
, under the map declaration, insert the following:
map.on('move', () => {
updateData();
});
Save your work.
To experiment with camera pitch, bearing, tilt, and zoom and get values to use in your code, try our Location Helper tool.
Final product
You have created a Svelte app that uses Mapbox GL JS to render a map, display the center coordinates and the zoom level of the map, and then update that display when a user interacts with the map.
The final App.svelte
page will look like the following:
<script>
import { onMount, onDestroy } from 'svelte';
import { Map } from 'mapbox-gl';
import '@site/src/node_modules/mapbox-gl/dist/mapbox-gl.css';
let map;
let mapContainer;
let lng, lat, zoom;
lng = -71.224518;
lat = 42.213995;
zoom = 9;
function updateData() {
zoom = map.getZoom();
lng = map.getCenter().lng;
lat = map.getCenter().lat;
}
onMount(() => {
const initialState = { lng: lng, lat: lat, zoom: zoom };
map = new Map({
container: mapContainer,
accessToken:YOUR_MAPBOX_ACCESS_TOKEN,
style: `mapbox://styles/mapbox/outdoors-v11`,
center: [initialState.lng, initialState.lat],
zoom: initialState.zoom
});
map.on('move', () => {
updateData();
});
});
onDestroy(() => {
map.remove();
});
</script>
<div>
<div class="sidebar">
Longitude: {lng.toFixed(4)} | Latitude: {lat.toFixed(4)} | Zoom:
{zoom.toFixed( 2 )}
</div>
<div class="map-wrap">
<div class="map" bind:this="{mapContainer}" />
</div>
</div>
<style>
.map {
position: absolute;
width: 100%;
height: 100%;
}
.sidebar {
background-color: rgb(35 55 75 / 90%);
color: #fff;
padding: 6px 12px;
font-family: monospace;
z-index: 1;
position: absolute;
top: 0;
left: 0;
margin: 12px;
border-radius: 4px;
}
</style>
Next steps
Now that you have created a Svelte app that uses Mapbox GL JS, you can explore examples using other JavaScript frameworks, such as React.