MapboxMap JS
The MapboxMap component and its family let you build Mapbox GL maps declaratively, straight from your HTML, with js-toolkit. A MapboxMap element owns the underlying Mapbox Map instance, and every other component (markers, popups, controls, sources, layers, images, clusters) is authored as a child element that registers itself against that map once it is loaded.
These components are published in the standalone @studiometa/ui-mapbox package and replace the @studiometa/vue-mapbox-gl library. If you are coming from the Vue library, read the migration guide.
Table of content
Installation
Install the package alongside its mapbox-gl peer dependency. The @mapbox/mapbox-gl-geocoder package is only required if you use the MapboxGeocoder component.
npm install @studiometa/ui-mapbox mapbox-gl
# Optional, only for the geocoder control
npm install @mapbox/mapbox-gl-geocoderThe Mapbox GL stylesheet is required for the map, its controls and popups to render correctly. Add it to your page, either as a <link> tag pointing to the CDN or by importing it from the package with your bundler.
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/v3.13.0/mapbox-gl.css" />/* or, when using a bundler */
@import 'mapbox-gl/dist/mapbox-gl.css';You will also need a Mapbox access token. Pass it to the MapboxMap component through the access-token option.
Usage
Register each component your page uses: a bare map with just a container needs only MapboxMap, and each marker, popup, control, source, layer, image or cluster you declare must be registered too. Registration order does not matter, because a child registered before its MapboxMap still wires up once the map connects.
Author the map with a root MapboxMap element holding a container ref, and give it a size through CSS.
import { registerComponent } from '@studiometa/js-toolkit';
import { MapboxMap } from '@studiometa/ui-mapbox';
registerComponent(MapboxMap);<div
data-component="MapboxMap"
data-option-access-token="<YOUR_MAPBOX_ACCESS_TOKEN>"
data-option-zoom="10"
data-option-center="[2.35, 48.86]"
class="h-96 w-full">
<div data-ref="container" class="h-full w-full"></div>
</div>@import 'mapbox-gl/dist/mapbox-gl.css';mapbox-gl is a heavy dependency (~230 kB gzipped, more with the geocoder), so the recommended default is to register the components as lazy manifest entries — see Lazy loading below.
Lazy loading
mapbox-gl is never in your main bundle: MapboxMap loads it with a dynamic import() when it mounts, and MapboxMap mounts only when the map nears the viewport, whether you register the class or a manifest entry. Registering the family as a manifest rather than as classes also defers the component modules. A manifest entry is a lazy importer plus a mount strategy, so a component module loads only when an element on the page declares its token, and only when its strategy allows.
The package ships its own manifest, which is the shortest way to get all of it:
import { registerManifest } from '@studiometa/js-toolkit';
import { manifest } from '@studiometa/ui-mapbox/manifest';
registerManifest(manifest);Every component is also available at its own subpath (@studiometa/ui-mapbox/<Component>), whose default export is the component class, so a hand-written manifest can carry only the components you use. Each component is registered independently, so list every one you declare: deferring MapboxMap pulls in mapbox-gl, but a marker or a cluster is its own module and needs its own entry.
import { registerManifest } from '@studiometa/js-toolkit';
registerManifest({
MapboxMap: {
mountStrategy: 'visible',
load: () => import('@studiometa/ui-mapbox/MapboxMap'),
},
MapboxMarker: {
mountStrategy: 'eager',
load: () => import('@studiometa/ui-mapbox/MapboxMarker'),
},
MapboxPopup: {
mountStrategy: 'eager',
load: () => import('@studiometa/ui-mapbox/MapboxPopup'),
},
});The map renders, so visible holds the mapbox-gl import back until a map approaches the viewport. A marker renders nothing, so its element carries hidden, and a popup nested in it is hidden with it. A standalone popup shows its content until the map is ready, unless its element carries hidden too. A hidden element never intersects the viewport, so give markers and popups eager, which waits for nothing beyond the element being on the page. This is what the package manifest already does — see Package defaults.
Reach for a different strategy when it fits better — idle, interaction, media:<query> — and override any of them per element with data-mount. The Autoloading guide lists all six.