Search code examples
javascriptleafletcustom-element

How to use a div inside a Shadow DOM as a Leaflet map container?


The JS based custom element below appear to work but can not find the mapid div that I add to the shadow DOM root. Is there a way in Leaflet or custom elements to allow stock Leaflet (version 1.4 which is the latest as of this writing) to find and use a shadow DOM-based mapid div?

error:

Uncaught Error: Map container not found.
    at NewClass._initContainer (Map.js:1102)
    at NewClass.initialize (Map.js:136)
    at new NewClass (Class.js:22)
    at Module.createMap (Map.js:1717)
    at new GDMap (gd-map.js:16)
    at gd-map.js:30
    at gd-map.js:31

I'm going on the approach that this simply is a case where Leaflet is looking for the mapid div in the dom root and can't find it in the shadow dom.

Javascript

import * as L from './leaflet/leaflet-src.esm.js';

(function () {
    class GDMap extends HTMLElement {
        constructor() {
            super();

            this.attachShadow({ mode: 'open' });
            this.shadowRoot.innerHTML = `<div style="height:180px" id="mapid"></div>`;

           var map = L.map('mapid').setView([51.505, -0.09], 13);

            L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'

            }).addTo(map);


            L.marker([51.5, -0.09]).addTo(map)
                .bindPopup('A pretty CSS3 popup.<br> Easily customizable.')
                .openPopup();

        }
    }
    window.customElements.define('geodex-map', GDMap);
})();

edited post to align div id as pointed out.. still same issue though.


Solution

  • Trying to instantiate a Leaflet map before its container is in the DOM is a known problem, with a known solution:

    The <div id="leafletmap"> must be added to the dom before calling L.map('leafletmap').

    But you already know this, because you're making a very good and specific question:

    Is there a way in [Leaflet 1.4] to find and use a shadow DOM-based mapid div?

    The answer is "no, but".

    If you read carefully the Leaflet API reference, you'll notice that a L.Map can be instantiated in two ways: either by providing the id of the HTMLElement that will be the map's container, or by providing the HTMLElement instance of the container.

    In other words, something along the lines of:

    var mapdiv = document.createElement('div');
    shadow.appendChild(mapdiv);
    var map = L.map(mapdiv)