All docsHelpTutorialsUse Mapbox GL JS in a React app

Use Mapbox GL JS in a React app

Intermediate
JavaScript
Prerequisite

Familiarity with React and front-end development concepts.

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 use-mapbox-gl-js-with-react.

In the use-mapbox-gl-js-with-react 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 use-mapbox-gl-js-with-react folder, create a folder called public. In the public folder, create one file:

  • index.html: This HTML file will display the rendered Mapbox map that your users will be able to interact with.

In the use-mapbox-gl-js-with-react folder, create another folder called src. In the src folder, create three files:

  • App.js: This JavaScript file will set up the React app.
  • index.css: This CSS file will contain styles to format the map and sidebar correctly.
  • index.js: This JavaScript file will render the Mapbox map to the browser.

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

use-mapbox-gl-js-with-react
package.json
public
index.html
src
App.js
index.css
index.js

Copy the following code into package.json:

package.json
{
"name": "use-mapbox-gl-js-with-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"mapbox-gl": "^2.6.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "^4.0.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
},
"eslintConfig": {
"extends": [
"react-app"
]
},
"browserslist": [
"defaults",
"not ie 11"
],
"author": "Mapbox",
"license": "MIT"
}

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 use-mapbox-gl-js-with-react 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>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Create a React web app that uses Mapbox GL JS to render a map"
/>
<title>Use Mapbox GL JS in a React app</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

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

Save your changes.

Create the React app

Open the src/index.js file. Add the following to import two stylesheets and the Mapbox GL JS map that you will build:

src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import 'mapbox-gl/dist/mapbox-gl.css';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

The first stylesheet contains the Mapbox GL JS styles to display the map. The second stylesheet is the index.css file that you created earlier, which is where you will add your app-specific CSS.

Add Mapbox GL JS

Open the src/App.js file. Add the following import statement to the top of the file:

src/App.js
import React, { useRef, useEffect, useState } from 'react';

Next, import Mapbox GL and add your access token. To use Mapbox GL with Create React App, you must add an exclamation point to exclude mapbox-gl from transpilation and disable the eslint rule import/no-webpack-loader-syntax. Set the mapboxgl accessToken property to the value of your Mapbox access token:

src/App.js
import mapboxgl from '!mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax
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 App.js:

src/App.js
export default function 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 App:

src/App.js
const mapContainer = useRef(null);
const map = useRef(null);
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/App.js
useEffect(() => {
if (map.current) return; // initialize map only once
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom
});
});

The Mapbox map is initialized within a React 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 useRef or ref if you are using class components. Later in this tutorial, you will assign the ref 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.
  • If you are using hooks, you also created a map useRef to store the initialize the map. The ref will prevent the map from reloading when the user interacts with the map.

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 App:

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

The mapContainer ref specifies that App 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 index.css file:

.map-container {
height: 400px;
}

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 no-unused-vars warnings. Don't worry — you use these variables 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. If you are using hooks, create an additional useEffect and add the following code. If you are using classes, add the following code inside componentDidMount():

src/App.js
useEffect(() => {
if (!map.current) return; // wait for map to initialize
map.current.on('move', () => {
setLng(map.current.getCenter().lng.toFixed(4));
setLat(map.current.getCenter().lat.toFixed(4));
setZoom(map.current.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/App.js
return (
<div>
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
</div>
<div ref={mapContainer} className="map-container" />
</div>
);

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

.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 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 index.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>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Create a React web app that uses Mapbox GL JS to render a map"
/>
<title>Use Mapbox GL JS in a React app</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

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

src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import 'mapbox-gl/dist/mapbox-gl.css';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

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

src/App.js
import React, { useRef, useEffect, useState } from 'react';
import mapboxgl from '!mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
export default function App() {
const mapContainer = useRef(null);
const map = useRef(null);
const [lng, setLng] = useState(-70.9);
const [lat, setLat] = useState(42.35);
const [zoom, setZoom] = useState(9);
useEffect(() => {
if (map.current) return; // initialize map only once
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom
});
});
useEffect(() => {
if (!map.current) return; // wait for map to initialize
map.current.on('move', () => {
setLng(map.current.getCenter().lng.toFixed(4));
setLat(map.current.getCenter().lat.toFixed(4));
setZoom(map.current.getZoom().toFixed(2));
});
});
return (
<div>
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
</div>
<div ref={mapContainer} className="map-container" />
</div>
);
}

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

src/index.css
.map-container {
height: 400px;
}
.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;
}

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.