Nuxt-Mapbox
Elegant Mapbox integration with Nuxt
🌟 NEW IN 1.4.0
- Overall Improved performance (ESM imports, less unnecessary Mapbox events)
- Full component reactivity (
define
composables now accept refs for reactivity) - New
useMapboxBeforeLoad
composable - Composables for accessing markers & popups
Features
- 🏗 Easily add Mapbox to your Nuxt app with Vue components
- 🌎 useMapbox Composable for easy access
- 👷 defineMapboxMarker & defineMapboxPopup for making custom components
- 🎛️ defineMapboxControl for creating your own controls
- 📖 Persistent map instances across routes
Quick Setup
- Add
nuxt-mapbox
&mapbox-gl
dependencies to your project
# Using pnpmpnpm add -D nuxt-mapbox mapbox-gl# Using yarnyarn add --dev nuxt-mapbox mapbox-gl# Using npmnpm install --save-dev nuxt-mapbox mapbox-gl
- Add
nuxt-mapbox
to themodules
section ofnuxt.config.ts
export default defineNuxtConfig({ modules: [ 'nuxt-mapbox' ]})
- Add your Mapbox API key to the
mapbox
section ofnuxt.config.ts
export default defineNuxtConfig({ modules: [ 'nuxt-mapbox' ], mapbox: { accessToken: '{API_KEY}' }})
Usage
View the Mapbox GL JS Docs for reference.
Map instances are created with components. You can provide all the options through component props
Example:
<MapboxMap map-id="{ID}" style="position: absolute; top: 0; bottom: 0; left: 250px; width: 500px;" :options="{ style: 'mapbox://styles/mapbox/light-v11', // style URL center: [-68.137343, 45.137451], // starting position zoom: 5 // starting zoom }" />
You can add Layers, Sources & Controls by nesting their respective components inside the Map
Examples:
<MapboxMap ... > <MapboxSource source-id="{ID}" :source="{ type: 'geojson', data: '/test.geojson' }" /> <MapboxLayer :layer="{ source: '{ID}', id: 'geojson-layer', type: 'fill' }" /> <MapboxGeolocateControl position="top-left" /> </MapboxMap>
Persistent Map Instances
For map instances to be persistent across routes, keepalive
must be set to true
in nuxt.config.ts.
This is done by the module automatically, but you can disable it by setting the persistent
option to false
in nuxt.config.ts
.
NOTE: Setting keepalive
to false will not have any effect, so if you need to have it disabled be sure to use persistent
instead
Events
All Map events are accessible directly through the component (With full Typescript support!)
View a list of events in the Mapbox Docs
Example:
<MapboxMap ... @load="exampleFunction" @click="exampleFunction" @resize="exampleFunction" >
You can access events directly on layers as well
Example:
<MapboxLayer ... @click="exampleFunction" >
Composables
useMapbox
The simplest way to access the map instance on setup is with the useMapbox composable. You must provide the map id.
The map instance will not be available until the page is fully loaded, so you must access it through a callback.
useMapbox(mapId, (map) => { // Do whatever with map here })
NOTE: The callback will only be run after the map has loaded (so if you do map.on('load')
, it will not work).
If you want to access the map before it has loaded, there is the useMapboxBeforeLoad
composable instead.
useMapbox
should be preferred over useMapboxBeforeLoad
with map.on('load')
to ensure that your code gets run on reactive updates while the map is already loaded.
useMapboxMarker & useMapboxPopup
You can access your markers and popups in the same way as useMapbox
with useMapboxMarker
& useMapboxPopup
!
Refs
When working with the map reactively (for example, in a watcher or computed method), you should instead use the map ref. The refs should be treated similar to Vue template refs.
It is important to remember that the refs will be undefined until they have been initialized, which will be after the component is mounted.
const mapRef = useMapboxRef(mapId); const markerRef = useMapboxMarkerRef(markerId); const popupRef = useMapboxPopupRef(markerId);
Linking Popups & Markers
You can have a popup linked to a marker by simply nesting the popup component inside the marker. Example:
<MapboxDefaultMarker marker-id="marker1" :options="{}" :lnglat="[110, 5]" > <MapboxDefaultPopup popup-id="popup1" :lnglat="[100, 0]" :options="{ closeOnClick: false }" > <h1 class="test"> Hello World! </h1> </MapboxDefaultPopup> </MapboxDefaultMarker>
Custom Components
While it is recommended to use the default components, making your own is easy with the built in composables!
Custom Popups & Markers
You can use defineMapboxPopup
& defineMapboxMarker
for custom marker & popup components
By passing a template ref you can put custom html directly into your component.
Be sure to nest your custom components inside a map instance so the map-id can be auto injected. You can also pass the map ID manually into the functions.
If you pass options
as a ref, the marker or popup will react to changes in settings.
Examples:
const popup = defineMapboxPopup(popupId, options, templateRef) popup?.setLngLat(lnglat)
NOTE: Because of the way markers are implemented in Mapbox, if passing a template ref to defineMapboxPopup you have to define properties in a callback like so:
const markerRef = defineMapboxMarker(markerId, options, templateRef, (marker) => { marker.setLngLat([110, 6]) })
Custom Controls
You can make your own control with the defineMapboxControl composable.
Example:
useMapbox(mapID, (map) => { if (htmlRef.value) { const control = defineMapboxControl((_map) => { return htmlRef.value as HTMLElement; }, (map) => {}) map.addControl(control); } })
Custom Map Component
If you would like to make your own map component, you can use defineMapboxInstance
Example:
// NOTE: Map instance will be null on server & until it is loaded on client const map = defineMapboxInstance(MAP_DIV_ID, options);
Custom Geocoder
If you want to use the geocoder without the map, use MapboxCustomGeocoder
instead.
You can even use your own inputs!
Example:
<MapboxCustomGeocoder v-model="result" /> <MapboxCustomGeocoder> <input> </MapboxCustomGeocoder>
const result = ref<MapboxGeocoder.Result>();
Development
# Install dependenciesnpm install# Generate type stubsnpm run dev:prepare# Develop with the playgroundnpm run dev# Build the playgroundnpm run dev:build# Run ESLintnpm run lint# Run Vitestnpm run testnpm run test:watch# Release new versionnpm run release