This example uses OpenLayers v10.9.0. The latest is v.
Edit

#### UTFGrid

utfgrid 1 tilejson 5

#####

This example shows how to read data from a UTFGrid source.

Point to a country to see its name and flag.

Tiles made with TileMill. Hosting on mapbox.com or with open-source TileServer.

##### main.js

    import Map from 'ol/Map.js';
    import Overlay from 'ol/Overlay.js';
    import View from 'ol/View.js';
    import TileLayer from 'ol/layer/Tile.js';
    import TileJSON from 'ol/source/TileJSON.js';
    import UTFGrid from 'ol/source/UTFGrid.js';

    const key = 'Your Mapbox access token from https://mapbox.com/ here';

    const mapLayer = new TileLayer({
      source: new TileJSON({
        url:
          'https://api.tiles.mapbox.com/v4/mapbox.geography-class.json?secure&access_token=' +
          key,
      }),
    });

    const gridSource = new UTFGrid({
      url:
        'https://api.tiles.mapbox.com/v4/mapbox.geography-class.json?secure&access_token=' +
        key,
    });

    const gridLayer = new TileLayer({source: gridSource});

    const view = new View({
      center: [0, 0],
      zoom: 1,
    });

    const mapElement = document.getElementById('map');
    const map = new Map({
      layers: [mapLayer, gridLayer],
      target: mapElement,
      view: view,
    });

    const infoElement = document.getElementById('country-info');
    const flagElement = document.getElementById('country-flag');
    const nameElement = document.getElementById('country-name');

    const infoOverlay = new Overlay({
      element: infoElement,
      offset: [15, 15],
      stopEvent: false,
    });
    map.addOverlay(infoOverlay);

    const displayCountryInfo = function (coordinate) {
      const viewResolution = view.getResolution();
      gridSource.forDataAtCoordinateAndResolution(
        coordinate,
        viewResolution,
        function (data) {
          // If you want to use the template from the TileJSON,
          //  load the mustache.js library separately and call
          //  info.innerHTML = Mustache.render(gridSource.getTemplate(), data);
          mapElement.style.cursor = data ? 'pointer' : '';
          if (data) {
            flagElement.src = 'data:image/png;base64,' + data['flag_png'];
            nameElement.innerHTML = data['admin'];
          }
          infoOverlay.setPosition(data ? coordinate : undefined);
        },
      );
    };

    map.on('pointermove', function (evt) {
      if (evt.dragging) {
        return;
      }
      const coordinate = map.getEventCoordinate(evt.originalEvent);
      displayCountryInfo(coordinate);
    });

    map.on('click', function (evt) {
      displayCountryInfo(evt.coordinate);
    });

##### index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>UTFGrid</title>
        <link rel="stylesheet" href="node_modules/ol/ol.css">
        <style>
          .map {
            width: 100%;
            height: 400px;
          }
          #country-name {
            color: black;
            font-size: 12pt;
            font-weight: bold;
            text-shadow: white 0.1em 0.1em 0.2em;
          }
        </style>
      </head>
      <body>
        <div id="map" class="map"></div>
        <div style="display: none;">
          <!-- Overlay with the country info -->
          <div id="country-info">
            <div id="country-name">&nbsp;</div>
            <img id="country-flag" />
          </div>
        </div>

        <script type="module" src="main.js"></script>
      </body>
    </html>

##### package.json

    {
      "name": "utfgrid",
      "dependencies": {
        "ol": "10.9.0"
      },
      "devDependencies": {
        "vite": "^3.2.3"
      },
      "scripts": {
        "start": "vite",
        "build": "vite build"
      }
    }