> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/help/llms.txt)

# Use Mapbox GL JS in a Vue app

[**Vue.js**](https://vuejs.org/) is a popular JavaScript web framework that focuses on declarative rendering and component composition. Since Vue and [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/) both manipulate the DOM, it is worth spending some time to understand how to combine the two.

In this tutorial, you will learn how to create a Vue web app that uses Mapbox GL JS to render a map. You will also learn how to respond to map events, and control the map from external events. By the end of this tutorial, you will have a basic Vue app that displays a map and updates the display when a user interacts with the map.

You will learn how to:

-   Set up a Vue app that uses Mapbox GL JS to render a map.
-   Display the center coordinates and zoom level of the map.
-   Update the display when a user interacts with the map.
-   Add a reset button to reset the map to its initial state.

The finished product of this tutorial is embedded below for you to explore. You can drag and zoom the map to see the coordinates and zoom level update in the sidebar. You can also click the "Reset" button to reset the map to its initial camera view.

If you'd like to get a Vue app running with **Mapbox GL JS** and are not interested in the additional learning of this tutorial use the Mapbox `npm create @mapbox/web-app` utility, choose Vue as your framework and scaffold your application in seconds.

```
$ npm create @mapbox/web-app
```

## Prerequisites

To get started, you will need:

-   **A Mapbox access token**: Find yours on the [Access token page](https://console.mapbox.com/account/access-tokens/) of your Developer Console.
-   **A Code editor**: A program like [Visual Studio Code](https://code.visualstudio.com/). **Node.js and npm.** [Download and install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) the latest version.
-   **Familiarity with Vue development.** Beginner experience with Vue and JavaScript.

## Create a new Vue App

To get started, create a Vue project using npm. Using your terminal, navigate to the directory where you want to create your Vue app. Then run the following command:

```bash
$ npm create vue@latest
```

You will be prompted to install `vue`. After successful installation, you will be prompted 4 questions by the CLI.

1.  **Project name (target directory):** - Name the project whatever you like.
2.  **Select features to include in your project:** - For this tutorial we are not using any of these features, press enter to skip.
3.  **Select experimental features to include in your project:** - Press enter to skip
4.  **Skip all example code and start with a blank Vue project?** - Select **No** for this question.

Then, in your command line, `cd` into the new Vue project directory and run the following command to install Mapbox GL JS:

```bash
$ npm install mapbox-gl
```

This will install the dependencies that your app requires, including Mapbox GL JS. This will create the file `package-lock.json` and the folder `node_modules`.

Setup is complete. You can now run the development server to make sure everything is working with the following command:

```bash
$ npm run dev
```

At this point the development server should be running, and you can view your app in your browser at `http://localhost:5173/`. You should see a Vue welcome message.

![Screenshot of the the Vue development server running with a welcome message.](https://docs.mapbox.com/help/assets/ideal-img/tutorials--use-mapbox-gl-js-with-vue--vue-welcome.c937e3a.480.png)

## Add a Map component

Next, you will create a Map component that uses Mapbox GL JS to render a map. This component will add a div to use as the map container, and its JavaScript code will instantiate a Mapbox GL JS map. For now it will only include the bare minimum to render a map, but you will add more functionality in the next steps.

### Create the Map component

To create the Map component, create a new file in the `src/components` directory called `Map.vue` and paste in the following code:

```js
<template>
  <div ref="mapContainer" class="map-container"></div>
</template>

<script>
import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";

export default {
  mounted() {
    const map = new mapboxgl.Map({
      accessToken: "YOUR_MAPBOX_ACCESS_TOKEN",
      container: this.$refs.mapContainer,
      style: "mapbox://styles/mapbox/standard",
    });

    // assign the map instance to this component's map property
    this.map = map;
  },

  // clean up the map instance when the component is unmounted
  unmounted() {
    this.map.remove();
    this.map = null;
  }
};
</script>

<style>
/* make the map container fill its parent */
.map-container {
  width: 100%;
  height: 100%;
}
</style>
```

In the `template` section above, you add a `div` element with a `ref` attribute that will be used to reference the map container in the JavaScript code. The `class` attribute is used to style the map container.

In the `script` section, you import Mapbox GL JS along with its CSS, and set the access token. Be sure to replace `YOUR_MAPBOX_ACCESS_TOKEN` with an access token from your [developer console](https://console.mapbox.com/account/access-tokens/). The `mounted` lifecycle hook is used to instantiate the map when the component is mounted. The `unmounted` lifecycle hook is used to clean up the map instance when the component is unmounted. Note that the map is instantiated without specifying a center or zoom level, so it will default to showing the globe.

In the `style` section, CSS is added to make the map container fill its parent element.

### Import the Map component into `App.vue`

To use your new `Map` component, you'll need to import it in `App.vue`. Replace the contents of `App.vue` with the following code:

```js
<template>
  <Map/>
</template>

<script>
import Map from "./components/Map.vue";

export default {
  components: { Map },
};
</script>

<style>
</style>
```

In the `template` section above, you render your new `Map` component.

In the `script` section, you import the `Map` component and add it to the `components` object so that it can be used in the template.

### CSS for root app element

Finally edit `src/assets/main.css` and replace the content within it with the snippet below:

```css
@import url('./base.css');

#app  {
  width: 100vw;
  height: 100vh;
}
```

This sets the height of the app's root element to 100% of the viewport height and width. This element is the map container's parent element, so it will make sure that the map fills the entire viewport.

Your development server should still be running, so you can view your app in your browser at `http://localhost:5173/`. If you stopped the server, you can restart it with the command `npm run dev`. You should now see a full screen map showing the globe. You can interact with the map by clicking and dragging to pan and scrolling to zoom.

![Screenshot of the Vue app with a Mapbox GL JS map showing the globe.](https://docs.mapbox.com/help/assets/ideal-img/tutorials--use-mapbox-gl-js-with-vue--map.42d42e4.480.png)

## Respond to Map Events

Next, you will add a UI element to display the map's center coordinates and zoom level. These values will update as the user interacts with the map, so you will need to listen for events and update the state of the app.

### Add UI and state management to App.vue

Start by updating `App.vue` to include a sidebar element to display the map's center coordinates and zoom level. The HTML for the sidebar uses Vue template syntax to bind the values to the `location` data property. The `location` object will hold the center coordinates and zoom level of the map. Pass the `location` object to the `Map` component using the [`v-model`](https://vuejs.org/api/built-in-directives.html#v-model) directive, which allows two-way data binding between the parent and child components.

In the `script` section, export a `data` function that returns an object with the `location` property. This will be used to store the map's center coordinates and zoom level. This example uses coordinates and zoom to show the city of Boston, Massachusetts.

In the `style` section, add some CSS to style the sidebar. The sidebar will be positioned in the top left corner of the viewport, and it will have a semi-transparent background color and some padding.

```js
<template>
  // highlight-start
  <div id="sidebar">
    Longitude: {{ location.center.lng.toFixed(4) }} | Latitude:
    {{ location.center.lat.toFixed(4) }} | Zoom:
    {{ location.zoom.toFixed(2) }} |
  </div>
  <Map v-model="location" />
  // highlight-end
</template>

<script>
import Map from "./components/Map.vue";

export default {
  components: { Map },
  // highlight-start
  data() {
    return {
      location: {
        center: { lng: -71.05987, lat: 42.35982 },
        zoom: 14,
      },
    };
  }
  // highlight-end
};
</script>

<style>
// highlight-start
#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;
}
// highlight-end
</style>
```

If you check the development server now, you should see the sidebar displaying the map's center coordinates and zoom level. These values will not update yet because you haven't added any event listeners to the map to update the `location` data property.

![Screenshot of the Vue app with a sidebar displaying the map's center coordinates and zoom level](https://docs.mapbox.com/help/assets/ideal-img/tutorials--use-mapbox-gl-js-with-vue--static-sidebar.6847c7f.480.png)

### Add map event listeners to update state

Next, you will update the `Map` component to listen for map events and update a data property named `location` in `App.vue`.

In the `script` section of `Map.vue`, add a `props` option to accept the `modelValue` prop. This prop contains the center and zoom values passed from the parent component.

Next, unpack the `center` and `zoom` values from the `modelValue` prop in the `mounted` lifecycle hook. These values will be used to set the initial center and zoom level of the map by adding them to the `Map()` options object.

Export a `methods` object with a method named `getLocation` that returns the current center and zoom level of the map by calling [`map.getCenter()`](https://docs.mapbox.com/mapbox-gl-js/api/map/#map#getcenter) and [`map.getZoom()`](https://docs.mapbox.com/mapbox-gl-js/api/map/#map#getzoom).

Finally, add event listeners to the map instance to listen for the [`move`](https://docs.mapbox.com/mapbox-gl-js/api/map/#map.event:move) and [`zoom`](https://docs.mapbox.com/mapbox-gl-js/api/map/#map.event:zoom) events. When these events are triggered, call the `getLocation` method you defined above and use Vue's [`$emit`](https://vuejs.org/api/options-state.html#emits) call to emit an event to update the `modelValue` prop in the parent component.

Review the code below and update your `Map.vue` file with each highlighted section.

```js
 <template>
  <div ref="mapContainer" class="map-container"></div>
</template>

<script>
import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";

export default {
  // highlight-start
  props: ["modelValue"],
  // highlight-end

  mounted() {
    // highlight-start
    const { center, zoom } = this.modelValue
    // highlight-end

    // instantiate the map using the center and zoom from the modelValue prop
    const map = new mapboxgl.Map({
      accessToken: "YOUR_MAPBOX_ACCESS_TOKEN",
      container: this.$refs.mapContainer,
      style: "mapbox://styles/mapbox/standard",
      // highlight-start
      center,
      zoom,
      // highlight-end
    });

    // highlight-start
    // function to update the modelValue prop with the map's current location
    const updateLocation = () =>
      this.$emit("update:modelValue", this.getLocation());

    // add event listeners to update the location on map move and zoom
    map.on("move", updateLocation);
    map.on("zoom", updateLocation);
    // highlight-end

    // assign the map instance to this component's map property
    this.map = map;
  },

  // clean up the map instance when the component is unmounted
  unmounted() {
    this.map.remove();
    this.map = null;
  },
  
  // highlight-start
  methods: {
    getLocation() {
      return {
        center: this.map.getCenter(),
        zoom: this.map.getZoom(),
      };
    },
  }
  // highlight-end
};
</script>

<style>
/* make the map container fill its parent */
.map-container {
  width: 100%;
  height: 100%;
}
</style>
```

Save your changes and view your app in the browser. You should see the new sidebar displaying the map's center coordinates and zoom level. As you pan and zoom the map, the values in the sidebar will update to reflect the current state of the map.

![Gif of the Vue app with a sidebar displaying the map's center coordinates and zoom level updating as the user interacts with the map](https://docs.mapbox.com/help/assets/ideal-img/tutorials--use-mapbox-gl-js-with-vue--map-events.480.gif)

## Control the map from external events

For the final step, you will add a reset button to the sidebar that resets the map to its initial state. This button will update the `location` data property in `App.vue` using the initial center coordinates and zoom level. The `Map` component will then respond to this change by flying the map to the new center and zoom level.

To add the reset button, update the `App.vue` template to include a button that resets the `location` data property to its initial state. The button will use Vue's inline [`@click`](https://vuejs.org/guide/essentials/event-handling.html#listening-to-events) handler to call a method that updates the `location` data property.

```js
<template>
  <div id="sidebar">
    Longitude: {{ location.center.lng.toFixed(4) }} | Latitude:
    {{ location.center.lat.toFixed(4) }} | Zoom:
    {{ location.zoom.toFixed(2) }} |
    // highlight-start
    <button
      @click="
        location = {
          center: { lng: -71.05987, lat: 42.35982 },
          zoom: 14,
        }
      "
    >
      Reset
    </button>
    // highlight-end
  </div>
  <Map v-model="location" />
</template>

<script>
import Map from "./components/Map.vue";

export default {
  components: { Map },
  data() {
    return {
      location: {
        center: { lng: -71.05987, lat: 42.35982 },
        zoom: 14,
      },
    };
  },
};
</script>

<style>
#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>
```

The button is updating the `location` data property on click, but the `Map` component is not yet set up to respond to changes in the `modelValue` prop. To make the map respond to changes in the `location` data property, you will need to add a watcher to the `Map` component.

The `watch` option in the `Map.vue` component will listen for changes to the `modelValue` prop. When the prop changes, it will check if the new values are different from the current values. If they are different, it will call the [`map.flyTo()`](https://docs.mapbox.com/mapbox-gl-js/api/map/#map#flyto) method to smoothly transition the map to the new center and zoom level.

Copy the highlighted snippet below into your `Map.vue` component.

```js
<template>
  <div ref="mapContainer" class="map-container"></div>
</template>

<script>
import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";

export default {
  props: ["modelValue"],

  mounted() {
    const { center, zoom } = this.modelValue

    // instantiate the map using the center and zoom from the modelValue prop
    const map = new mapboxgl.Map({
      accessToken: "pk.eyJ1IjoiY2hyaXN3aG9uZ21hcGJveCIsImEiOiJjbDl6bzJ6N3EwMGczM3BudjZmbm5yOXFnIn0.lPhc5Z5H3byF_gf_Jz48Ug",
      container: this.$refs.mapContainer,
      style: "mapbox://styles/mapbox/standard",
      center: center,
      zoom,
    });

    // function to update the modelValue prop with the map's current location
    const updateLocation = () =>
      this.$emit("update:modelValue", this.getLocation());

    // add event listeners to update the location on map move and zoom
    map.on("move", updateLocation);
    map.on("zoom", updateLocation);

    // assign the map instance to this component's map property
    this.map = map;
  },

  // clean up the map instance when the component is unmounted
  unmounted() {
    this.map.remove();
    this.map = null;
  },
  
  // highlight-start
  // watch for external changes to the modelValue prop and update the map accordingly
  watch: {
    modelValue(next) {
      const curr = this.getLocation();

      // Only flyTo if any of the values have changed
      if (
        curr.center.lng !== next.center.lng ||
        curr.center.lat !== next.center.lat ||
        curr.zoom !== next.zoom
      ) {
        this.map.flyTo({
          center: next.center,
          zoom: next.zoom,
        });
      }
    },
  },
  // highlight-end
  
  methods: {
    getLocation() {
      return {
        center: this.map.getCenter(),
        zoom: this.map.getZoom(),
      };
    },
  },
};
</script>

<style>
/* make the map container fill its parent */
.map-container {
  width: 100%;
  height: 100%;
}
</style>

```

Your app should now have a reset button that resets the map to its initial state when clicked. The map will smoothly transition to the new center and zoom level using the `flyTo` method as in the embedded demo below.

## Next steps

🎉 **Congratulations** on completing this tutorial! You're ready to continue building out a full-featured mapping application in Vue.

### What we covered

-   How to set up a Vue app that uses Mapbox GL JS to render a map.
-   How to display the center coordinates and zoom level of the map.
-   How to update the display when a user interacts with the map.
-   How to add a reset button to reset the map to its initial state.

### Things to try

-   Add more UI elements to control the map, such as buttons to pan and zoom the map, or a dropdown to change the map style.
-   Add a search bar using [Mapbox Search JS](https://docs.mapbox.com/mapbox-search-js/) to allow users to search for locations and fly the map to those locations.
-   Add Markers to the map using the [Marker](https://docs.mapbox.com/mapbox-gl-js/api/markers/) class in Mapbox GL JS.

### Learn more

-   Explore the [Mapbox GL JS documentation](https://docs.mapbox.com/mapbox-gl-js/api/) to learn more about the Mapbox GL JS API.
-   See the [Mapbox GL JS examples](https://docs.mapbox.com/mapbox-gl-js/example/) for more ideas on how to use Mapbox GL JS in your app.
-   See the [Vue documentation](https://vuejs.org/v2/guide/) to learn more about Vue.