All docsHelpTutorialsUse Mapbox GL JS in a React app

Use Mapbox GL JS in a React app

React is a popular JavaScript library used for building user interfaces. Since React manipulates the DOM, it can be confusing to connect React 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 React 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 React and Mapbox GL JS. This tutorial shows code for React Hooks and Class Components.

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.
  • Node.js and npm. To run the commands necessary to run your React app locally, install Node.js and npm.
  • Working familiarity with React. You don't need to have a lot of experience using React to complete this tutorial, but you should be familiar with the underlying concepts and workflows.

Set up the React app structure

To get started, create a new folder called mapboxAndReact.

In the mapboxAndReact folder, create a new file:

  • package.json: This file is used to specify all of the Node packages that your app requires, including React and Mapbox GL JS.

In the mapboxAndReact folder, create a folder called public. In the public folder, create two new files:

  • index.html: This HTML file will display the rendered Mapbox map that your users will be able to interact with.
  • site.css: This file will contain the CSS necessary to format the map and sidebar correctly.

In the mapboxAndReact folder, create another folder called src. In the src folder, create a new file:

  • index.js: This JavaScript file will hold all of the React logic necessary to set and manage the app state and render the Mapbox map to the browser.

Once you have created these folders and files, you will have the following file structure:

mapboxAndReact
package.json
public
index.html
site.css
src
index.js

Copy the following code into package.json:

package.json
{
"name": "mapboxAndReact",
"description": "Create a React web app that uses Mapbox GL JS to render a map.",
"version": "1.0.0",
"main": "src/index.js",
"dependencies": {
"mapbox-gl": "^2.1.1",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"react-scripts": "^4.0.1",
"worker-loader": "^3.0.7"
},
"scripts": {
"start": "react-scripts start"
},
"browserslist": [
"defaults"
],
"author": "Mapbox",
"license": "MIT",
"homepage": "https://docs.mapbox.com/help/tutorials/use-mapbox-gl-js-with-react/"
}

In addition to the React-specific Node packages react and react-dom, this file also requires react-scripts which is also known as Create React App to build the app, and mapbox-gl to access Mapbox GL JS.

Save your changes.

In the command line, navigate into the mapboxAndReact folder you created. In that folder, run the command npm install, which will install all the Node packages that you specified in the package.json file. This step also creates the package-lock.json file.

Create the HTML page

Open the public/index.html file and paste the following code into it:

public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Mapbox GL JS and React</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://api.tiles.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css"
rel="stylesheet"
/>
<link href="%PUBLIC_URL%/site.css" rel="stylesheet" />
</head>
<body>
<div id="app"></div>
</body>
</html>

This code creates the structure of the HTML page your users will see. There is a <div> element with the ID app in the <body> of the page. This <div> is the container in which the React app will be rendered on the page.

This code also links to two different stylesheets in the <head>. The first stylesheet is the Mapbox GL JS stylesheet, which ensures that the elements in your map are displayed correctly. The second stylesheet is the site.css file that you created earlier, which is where you will add your app-specific CSS.

Save your changes.

Create the React app

Open the src/index.js file. Add the following import statements to the top of the file:

src/index.js
import React, { useRef, useEffect, useState } from 'react';
import ReactDOM from 'react-dom';

Next, import Mapbox GL and add your access token. To use Mapbox GL with Create React App, load Mapbox GL JS's WebWorker. Set the mapboxgl accessToken property to the value of your Mapbox access token:

src/index.js
import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp';
import MapboxWorker from 'worker-loader!mapbox-gl/dist/mapbox-gl-csp-worker';
mapboxgl.workerClass = MapboxWorker;
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';

Now you can set up the React app! To create the structure that you will add the code from the next few steps in, add the following to the bottom of index.js:

src/index.js
const Map = () => {
};
ReactDOM.render(<Map />, document.getElementById('app'));

This defines Map then specifies that it should be rendered in the <div> with the ID of app.

Save your changes.

Set the app's default state

Next, you will create some defaults for your app to use for the initial latitude, longitude, and zoom of the map. Add the following inside Map:

src/index.js
const mapContainer = useRef();
const [lng, setLng] = useState(-70.9);
const [lat, setLat] = useState(42.35);
const [zoom, setZoom] = useState(9);

The state stores the longitude, latitude, and zoom for the map. These values will all change as your user interacts with the map.

Next, initialize the map. The following code will be invoked right after the app is inserted into the DOM tree of your HTML page.

src/index.js
useEffect(() => {
const map = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom
});
return () => map.remove();
}, []);

The Mapbox map is initialized within React's Effect hook or the componentDidMount() lifecycle method, if you are using classes. Initializing your map here ensures that Mapbox GL JS will not try to render a map before React creates the element that contains the map. You also set the following options inside the map initialization:

  • The container option tells Mapbox GL JS to render the map inside a specific DOM element. Here, the app expects to receive a mapContainer ref. Later in this tutorial, you will assign the ref that is being referenced here to an HTML element that will act as the map container.
  • The style option defines the style that the map will use (mapbox://styles/mapbox/streets-v11).
  • The center and zoom options set the center coordinates and zoom level of the map using the values of lng, lat, and zoom that are stored in state.

Save your changes.

Render the map

Now you need to render the map in your app. The entry point to initialize a Mapbox map in a React app is through a single element provided in the return statement. Add the following code to your app above the closing curly brace of Map:

src/index.js
return (
<div>
<div className="map-container" ref={mapContainer} />
</div>
);

The mapContainer ref specifies that map should be drawn to the HTML page in a new <div> element.

The map needs a few styling rules to render correctly. Add the following code to the site.css file:

.map-container {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}
show hidden lines

Save your changes. In the command line, run the command npm start. This starts a local server and opens a new page in your browser that contains the new Mapbox map.

If you open your browser's developer console you may see an error: 'map' is assigned a value but never used. Don't worry — you will be using the map variable in the next step!

Store the new coordinates

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 a Mapbox GL JS map.on('move') function that sets the state to these new values when a user moves the map. Within useEffect if you are using hooks, or in componentDidMount() if you are using classes, add the following code:

src/index.js
map.on('move', () => {
setLng(map.getCenter().lng.toFixed(4));
setLat(map.getCenter().lat.toFixed(4));
setZoom(map.getZoom().toFixed(2));
});

This function uses useState() if you are using hooks, or setState() if you are using classes, to reset the values of lng, lat, and zoom when the map moves. It also uses the following methods:

  • getCenter(), a Mapbox GL JS method, to get the new longitude and latitude of the point at the center of the map.
  • getZoom(), a Mapbox GL JS method, to determine the zoom level that the map is set to.
  • toFixed(), a JavaScript method, to truncate the resulting floating point number to the specified number of digits.

Display the coordinates

Now that you are able to collect and store this information, you can use return to display it on the map. Inside the opening tag of the <div> you created to hold the map, add a new <div> to display the longitude, latitude, and zoom of the map. The return statement will look like this now:

src/index.js
return (
<div>
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
</div>
<div className="map-container" ref={mapContainer} />
</div>
);

The sidebar needs a few styling rules to display on the page correctly. Add the following CSS to the site.css file:

show hidden lines
.sidebar {
background-color: rgba(35, 55, 75, 0.9);
color: #ffffff;
padding: 6px 12px;
font: 15px/24px monospace;
z-index: 1;
position: absolute;
top: 0;
left: 0;
margin: 12px;
border-radius: 4px;
}

Save your work and go back to the browser page. There is a sidebar now in the upper left corner of the map that is styled according to the CSS rules you set in site.css. The sidebar shows the current latitude and longitude of the center of the map, as well as the zoom level. Now when you zoom and pan around the map, the contents of the sidebar will update.

Final product

You have created a React 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 index.html page will look like the following:

public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Mapbox GL JS and React</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://api.tiles.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css"
rel="stylesheet"
/>
<link href="%PUBLIC_URL%/site.css" rel="stylesheet" />
</head>
<body>
<div id="app"></div>
</body>
</html>

The final index.js file will look like the following:

src/index.js
import React, { useRef, useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp';
import MapboxWorker from 'worker-loader!mapbox-gl/dist/mapbox-gl-csp-worker';
mapboxgl.workerClass = MapboxWorker;
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
const Map = () => {
const mapContainer = useRef();
const [lng, setLng] = useState(-70.9);
const [lat, setLat] = useState(42.35);
const [zoom, setZoom] = useState(9);
useEffect(() => {
const map = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom
});
map.on('move', () => {
setLng(map.getCenter().lng.toFixed(4));
setLat(map.getCenter().lat.toFixed(4));
setZoom(map.getZoom().toFixed(2));
});
return () => map.remove();
}, []);
return (
<div>
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
</div>
<div className="map-container" ref={mapContainer} />
</div>
);
};
ReactDOM.render(<Map />, document.getElementById('app'));

The final site.css file will look like:

public/site.css
.map-container {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}
.sidebar {
background-color: rgba(35, 55, 75, 0.9);
color: #ffffff;
padding: 6px 12px;
font: 15px/24px monospace;
z-index: 1;
position: absolute;
top: 0;
left: 0;
margin: 12px;
border-radius: 4px;
}

Next steps

Now that you have created a React app that uses Mapbox GL JS, you can explore other, more complex examples in the Mapbox React examples GitHub repository.