How to display a map in Svelte using MapLibre GL JS
In this tutorial, you’ll learn how to create a Svelte component to render a map using MapLibre GL JS. Together we will make a simple fullscreen map application as an example of how to use MapTiler maps together with Svelte and MapLibre GL JS for your Svelte app.
By the end of this tutorial, you will be able to create a full-screen map with a marker at a specified location. Your final map will look like this:
Getting started
Minimal requirements for completing this tutorial.
- Basic Svelte knowledge. You don’t need a lot of experience using Svelte for this tutorial, but you should be familiar with basic concepts and workflow.
- MapTiler API key. Your MapTiler account access key is on your MapTiler Cloud account page or Get API key for FREE.
- MapLibre GL JS. JavaScript library for building web maps. In this tutorial, you will learn how to install it.
- Node.js and npm. Necessary to run your Svelte app locally. Node.js
Create an app
In this step, we are going to learn how to create a Svelte app.
To create a new Svelte project, run in your command-line:
npx degit sveltejs/template my-svelte-map
Navigate to the newly created project folder my-svelte-map
cd my-svelte-map
Inside the newly created project folder, run npm install
to install the dependencies.
To start your local environment, run npm run dev
. You will find your app running on address http://localhost:5000/
.
Now you should see the app in your browser.
Installation and setting up
To install MapLibre GL library, navigate to your project folder and run the command:
npm i maplibre-gl
Navigate to the public
folder and delete all the content of the global.css
file. Write these lines in the global.css
file
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
Now navigate to the src
folder and delete the props name of the main.js
file. Your main.js
file should look like this:
import App from './App.svelte';
const app = new App({
target: document.body,
props: {}
});
export default app;
Delete all the content of the App.svelte
file and write the following lines in the App.svelte
file
<script>
</script>
<div class="app">
This is my map App
</div>
<style>
.app {
text-align: center;
}
</style>
Now you should see “This is my map App“ in your browser.
Create a navbar component
In this step, we will create a simple heading navbar component.
Create a new folder called components
inside the src
folder.
Create a new file called Navbar.svelte
inside the components
folder and write these lines:
<div class="heading">
<h1>This is my map App</h1>
</div>
<style>
.heading {
margin: 0;
padding: 0px;
background-color: black;
color: white;
}
.heading > h1 {
padding: 20px;
margin: 0;
}
</style>
Finally, to display the Navbar
we need to import the Navbar component and add it to our main component App.svelte
.
Import the navbar component into App.svelte
script block
<script>
import Navbar from './components/Navbar.svelte';
</script>
Replace the text ‘This is my map App’ with <Navbar />
. Your App.svelte
file should look like this:
<script>
import Navbar from './components/Navbar.svelte';
</script>
<div class="app">
<Navbar />
</div>
<style>
.app {
text-align: center;
}
</style>
Now you should see the black navbar at the top of your browser.
Create a map component
In this step, we will create a simple map component.
Create a new file called Map.svelte
inside the components folder and write these lines:
<script>
import { onMount, onDestroy } from 'svelte'
import { Map } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
let map;
let mapContainer;
onMount(() => {
const apiKey = 'YOUR_MAPTILER_API_KEY';
const initialState = { lng: 139.753, lat: 35.6844, zoom: 14 };
map = new Map({
container: mapContainer,
style: `https://api.maptiler.com/maps/streets/style.json?key=${apiKey}`,
center: [initialState.lng, initialState.lat],
zoom: initialState.zoom
});
});
onDestroy(() => {
map.remove();
});
</script>
<div class="map-wrap">
<a href="https://www.maptiler.com" class="watermark"><img
src="https://api.maptiler.com/resources/logo.svg" alt="MapTiler logo"/></a>
<div class="map" id="map" bind:this={mapContainer}></div>
</div>
<style>
.map-wrap {
position: relative;
width: 100%;
height: calc(100vh - 77px); /* calculate height of the screen minus the heading */
}
.map {
position: absolute;
width: 100%;
height: 100%;
}
.watermark {
position: absolute;
left: 10px;
bottom: 10px;
z-index: 999;
}
</style>
We use position: absolute
on the map itself and position: relative
on the wrap around the map for more possibilities in future styling.
Here you will need to replace YOUR_MAPTILER_API_KEY
with your actual MapTiler API key.
- The
container
option sets the DOM element in which the map will be rendered. We will assign themapContainer
ref expected by our component to an HTML element, which will act as a container. Keep in mind that the reference tomapContainer
can only be used after the execution of theonMount
lifecycle function. - The
style
option defines what style the map is going to use. - The
center
andzoom
options set the starting position of the map.
The onDestroy
function does the cleanup that should occur when the instance is destroyed.
Finally, to display the Map
we need to import the Map component and add it to our main component App.svelte
.
Import the map component into App.svelte
script block
<script>
import Navbar from './components/Navbar.svelte';
import Map from './components/Map.svelte';
</script>
Add the <Map />
just below the Navbar in the template section. The template block should look like this
<div class="app">
<Navbar />
<Map />
</div>
With everything done up until now, you should be able to see your beautiful map in your browser.
Your App.svelte
file should look like this:
<script>
import Navbar from './components/Navbar.svelte';
import Map from './components/Map.svelte';
</script>
<div class="app">
<Navbar />
<Map />
</div>
<style>
.app {
text-align: center;
}
</style>
Basic additional options
The last topic of this tutorial will be adding basic objects to your map. For more detailed information, you can visit the MapLibre documentation.
Map Controls
We will navigate back to our Map.svelte
file and add map navigation controls to our map.
Add the NavigationControl
next to the Map object import from MapLibre GL.
import { Map, NavigationControl } from 'maplibre-gl';
On line 21 (just after the initialization of the map) of the Map.svelte
file, add the following line:
map.addControl(new NavigationControl(), 'top-right');
new NavigationControl()
will create new controls object which we add to current map using the addControl()
function in the 'top-right'
position.
Marker
Another essential thing to add to your map could be a marker of some location.
Add the Marker
next to the Map object import from MapLibre GL.
import { Map, NavigationControl, Marker } from 'maplibre-gl';
In the following line where we declare the navigation control, we add these lines:
new Marker({color: "#FF0000"})
.setLngLat([139.7525,35.6846])
.addTo(map);
We create a new marker using the .marker
function. We added the color option to make it red, then set Lng/Lat of the marker using .setLngLat()
function, and finally added it to the current map using .addTo()
function.
We finished our basic map objects and your Map.svelte
file should look like this:
<script>
import { onMount, onDestroy } from 'svelte'
import { Map, NavigationControl, Marker } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
let map;
let mapContainer;
onMount(() => {
const apiKey = 'YOUR_MAPTILER_API_KEY';
const initialState = { lng: 139.753, lat: 35.6844, zoom: 14 };
map = new Map({
container: mapContainer,
style: `https://api.maptiler.com/maps/streets/style.json?key=${apiKey}`,
center: [initialState.lng, initialState.lat],
zoom: initialState.zoom
});
map.addControl(new NavigationControl(), 'top-right');
new Marker({color: "#FF0000"})
.setLngLat([139.7525,35.6846])
.addTo(map);
});
onDestroy(() => {
map.remove();
});
</script>
<div class="map-wrap">
<a href="https://www.maptiler.com" class="watermark"><img
src="https://api.maptiler.com/resources/logo.svg" alt="MapTiler logo"/></a>
<div class="map" id="map" bind:this={mapContainer}></div>
</div>
<style>
.map-wrap {
position: relative;
width: 100%;
height: calc(100vh - 77px); /* calculate height of the screen minus the heading */
}
.map {
position: absolute;
width: 100%;
height: 100%;
}
.watermark {
position: absolute;
left: 10px;
bottom: 10px;
z-index: 999;
}
</style>
Full code to download
We have created a template with the result of this tutorial that will serve as a basis to build future applications. You can access the template repository at Svelte template for MapLibre.
Online demo:
You can see an online demo at https://labs.maptiler.com/svelte-template-maplibre-gl-js/
Conclusion
Congratulations! You have finished your simple fullscreen map app using Svelte, showing Tokyo with a marker on Tokyo Imperial Palace. You can explore more about MapLibre GL JS for your map in the MapLibre API reference.
Useful links
MapLibre GL JS
Svelte
NPM - MapLibre GL
MapLibre official web
MapTiler Cloud - customize tool
Related guides
- Automatically created API key
- Check if MapLibre GL JS is supported
- Coordinates API
- Dataset upload - formats and limits
- Difference between 256x256, 512x512, and HiDPI/Retina rasterized tiles
- Exported Tiles Multiplier
- Generalization in maps
- How are the tile requests cached in web browser?
- How MapTiler map tiles are Generated and Delivered
- How to add Geocoding control to Maplibre GL JS map