I'm working on a custom Gutenberg block that uses the Mapbox GL JS API for displaying a map. To create the map I have to call the following constructor.
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/mapbox/streets-v12', // style URL
center: [-74.5, 40], // starting position [lng, lat]
zoom: 9 // starting zoom
});
According to the documentation, the container
property can be either a string with the ID of the container or an instance of an HTMLElement
. Since my implementation is a Gutenberg block, I went with the latter by using useRef
from the @wordpress/element
package to reference the container element.
The following code is my implementation:
import mapboxgl from 'mapbox-gl';
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { useEffect, useRef, useState } from '@wordpress/element';
mapboxgl.accessToken = '*myaccesstoken*';
const Edit = ({ attributes, setAttributes }) => {
const blockProps = useBlockProps();
const mapContainer = useRef(null);
const mapRef = useRef(null);
const [lng, setLng] = useState(-70.9);
const [lat, setLat] = useState(42.35);
useEffect(() => {
if (mapRef.current !== null || mapContainer.current === null) {
return;
}
mapRef.current = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v12',
center: [lng, lat],
zoom: 9
});
}, []);
return (
<div {...blockProps}>
<div id="map" ref={mapContainer}></div>;
</div>
)
};
export default Edit;
Whenever I use this block in the Full Site Editing (FSE) mode, the mapboxgl.Map
constructor throws the following error:
Error: Invalid type: 'container' must be a String or HTMLElement.
(This doesn't happen whenever the block is used on a single post).
When logging mapContainer.current
I can see the <div #map>
element being logged, though the constructor is not accepting it. Is the element referenced in useRef
somehow not an actual HTMLElement
instance?
I based my implementation on this Mapbox + React tutorial from their own site.
Selecting a random element outside the block with the DOM API does work as expected. For example container: document.getElementById('some-id')
. This does indicate that the API works.
Selecting the <div #map>
from within the useEffect
hook with the DOM API results in the element not being found.
container: 'map' // -> Error: Container 'map' not found
container: document.getElementById('map') // -> Error: Invalid type: 'container' must be a String or HTMLElement
<div id="map"></div>
, and then the map should initialize correctly by simply passing the container'sid
-useEffect( () => { const map = new mapboxgl.Map( { container: 'map' } ); ... }, [] )
, or the container's element - just replace the'map'
withdocument.getElementById( 'map' )
. Have you already tried any of that?container: 'map'
andcontainer: document.getElementById('map')
fail to find the element. The former throws the errorError: Container 'map' not found
and the latter show the error mentioned in the question. I've also turned to the react-map-gl package (a React wrapper for the Mapbox GL JS API) but that too threw the same error as in the question.import mapboxgl from 'mapbox-gl';
) and 52 (mapLib={mapboxgl}
) - I've already tried removing them and your block still worked fine. see screenshot here