All docschevron-rightHelpchevron-rightarrow-leftTutorialschevron-rightUse Mapbox GL JS in a Svelte app

Use Mapbox GL JS in a Svelte app

Intermediate
codeJavaScript
Prerequisite

Familiarity with Svelte and front-end development concepts.

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 your Account page.
  • 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 repo. 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 ensure your app will use all of the space available in the browser window:

<style>
  body {
	margin: 0;
	padding: 0;
  }
</style>

Now you should be set up, and have the following file structure:

folder use-mapbox-gl-js-with-svelte
folder node_modules
folder public
code favicon.ico
code global.css
code index.html
folder scripts
code setupTypeScript.js
folder src
code App.svelte
code main.js
code .gitignore
code package-lock.json
code package.json
document README.md
code rollup.config.js

Save your changes.

Create the Svelte app

All of 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 currently 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 in order 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 in order to give your app acess to Mapbox GL JS's CSS properties:

import "../node_modules/mapbox-gl/dist/mapbox-gl.css"

Add variables

In order 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 in 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 in order to work, such as the map's center and style. One such attribute is the map's container. This container is meant to be an HTML element, such as a <div>, that the map can live inside.

To accomplish this, we will use Svelte binding. In 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. In 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; however, it looks basic and does not update with map movement.

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: rgba(35, 55, 75, 0.9);
  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 info

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.

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 "../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: rgba(35, 55, 75, 0.9);
		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.