Mapbox GL JS + React: Reactive Tooltip

See https://github.com/mapbox/mapbox-react-examples/

by Tristen Brown

HTML

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/v0.39.1/mapbox-gl.css">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-assembly/mbx/v0.18.0/assembly.min.css">
<script src="https://api.mapbox.com/mapbox-assembly/mbx/v0.18.0/assembly.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/v0.39.1/mapbox-gl.js"></script>
<div id="app"></div>

Babel + JSX

/* See https://github.com/mapbox/mapbox-react-examples/ for full example */

mapboxgl.accessToken = 'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA';

class Tooltip extends React.Component {
  render() {
    const { features } = this.props;

    const renderFeature = (feature, i) => {
      return (
        <div key={i}>
          <strong className='mr3'>{feature.layer['source-layer']}:</strong>
          <span className='color-gray-light'>{feature.layer.id}</span>
        </div>
      )
    };

    return (
      <div className="flex-parent-inline flex-parent--center-cross flex-parent--column absolute bottom">
        <div className="flex-child px12 py12 bg-gray-dark color-white shadow-darken10 round txt-s w240 clip txt-truncate">
          {features.map(renderFeature)}
        </div>
        <span className="flex-child color-gray-dark triangle triangle--d"></span>
      </div>
    );
  }
}

class Application extends React.Component {
  tooltipContainer;

  setTooltip(features) {
    if (features.length) {
      ReactDOM.render(
        React.createElement(
          Tooltip, {
            features
          }
        ),
        this.tooltipContainer
      );
    } else {
    	ReactDOM.unmountComponentAtNode(this.tooltipContainer)
    }
  }

  componentDidMount() {

    // Container to put React generated content in.
    this.tooltipContainer = document.createElement('div');

    const map = new mapboxgl.Map({
      container: this.mapContainer,
      style: 'mapbox://styles/mapbox/streets-v9',
      center: [-79.38, 43.65],
      zoom: 12.5
    });

    const tooltip = new mapboxgl.Marker(this.tooltipContainer, {
      offset: [-120, 0]
    }).setLngLat([0,0]).addTo(map);
    
    map.on('mousemove', (e) => {
      const features = map.queryRenderedFeatures(e.point);
      tooltip.setLngLat(e.lngLat);
      map.getCanvas().style.cursor = features.length ? 'pointer' : '';
      this.setTooltip(features);
    });
  }

 ...