How can I disable or change the href on a React-Leaflet v4 Popup close button?

Viewed 1173

In react-leaflet v4, the Popup component has a default href associated with the close button that directs to #close. Is there a way in React to modify this href or disable the href redirection? It's breaking my react-dom HashRouter.

Of note, Popup.js in Leaflet 1.8 has the following code:

var closeButton = this._closeButton = DomUtil.create('a', prefix + '-close-button', container);
closeButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399
closeButton.setAttribute('aria-label', 'Close popup');
closeButton.href = '#close';
closeButton.innerHTML = '<span aria-hidden="true">&#215;</span>';
4 Answers

Try something like this. It will probably disable any other hrefs that you may have in the popup though.

document.querySelector('.leaflet-pane.leaflet-popup-pane')!.addEventListener('click', event => {
        event.preventDefault();
});

The same issue is also in angular - means it seems to be the leaflet Lib:

    // leaflet.js
    close: function () {
        if (this._map) {
            this._map.removeLayer(this);
        }
        return this;
    },

The close function has not even the $event as an argument and the "default" isn't prevented. This leaves us only dirty hacks:

  1. Get the close button after the marker was displayed
  2. Add a click handler more
  3. Add a prefentDefault
  yourMethodOpensTheToolTip(marker: Marker) {
    if (marker && marker.openPopup) {
      marker.openPopup();
      // 1. get the close buttons, after the opened the popup
      const closeButtons = document.getElementsByClassName('leaflet-popup-close-button');
      // 2. add the event handler - if you have more than one, loop here
      if (closeButtons && closeButtons.length > 0) {
        L.DomEvent.on(closeButtons[0] as HTMLElement, 'click', function(ev){
          ev.preventDefault(); // 3. stop it here
        });
      }

Just for reference the #close button as HTML: #close a tag

You can utilize useRef hooks and create a click event in the marker

const mapRef = useRef(null);

// event listener to handle marker click
const handleClick = () => {
    mapRef.current._popup._closeButton.addEventListener('click', (event) => {
     event.preventDefault();
    })
};

const map = (<MapContainer center={position} zoom={13} scrollWheelZoom={false} style={{ height: '350px', width: '100%' }} ref={mapRef}>
    <TileLayer
      attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
    />
    <Marker
      position={position}
      eventHandlers={{
        click: (e) => handleClick(),
      }}
    >
      <Popup>
        A pretty CSS3 popup. <br /> Easily customizable.
      </Popup>
    </Marker>
  </MapContainer>)

if you are using GeoJSON you can use onEachFeature props

const onEachCountry = (country, layer) => {
const countryName = country.properties.ADMIN;
layer.on('click', function (e) {
  layer
    .bindPopup(countryName)
    .openPopup()
    ._popup._closeButton.addEventListener('click', (event) => {
      event.preventDefault();
    });
}); 
};

const map = (<MapContainer style={{ height: '300px' }} zoom={1} center={[20, 100]}>
    <GeoJSON style={countryStyle} data={mapData.features} onEachFeature={onEachCountry} />
  </MapContainer>)

In my React project with react-leaflet v4, I had the same issue and I solved it with the "popupopen" event :

https://leafletjs.com/reference.html#marker-popupopen

<Marker
    position={position}
    eventHandlers={{
        popupopen: (e) => {
            e.popup._closeButton.removeAttribute("href");
            e.popup._closeButton.style.cursor = "pointer";
        }
    }}
>
    <Popup>
        <p>Lorem ipsum dolor sit amet</p>
    </Popup>
</Marker>

I hope it will help.

Related