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

#### Layer Groups

tilejson 5 input 1 bind 1 group 1 layergroup 2

#####

##### Click on layer nodes below to change their properties.

- OSM layer
  visible opacity
- Layer group
  visible opacity
  - Food insecurity layer
    visible opacity
  - World borders layer
    visible opacity

Example of a map with layer group.

Example of a map with layer group.

##### main.js

    import Map from 'ol/Map.js';
    import View from 'ol/View.js';
    import LayerGroup from 'ol/layer/Group.js';
    import TileLayer from 'ol/layer/Tile.js';
    import {fromLonLat} from 'ol/proj.js';
    import OSM from 'ol/source/OSM.js';
    import TileJSON from 'ol/source/TileJSON.js';

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

    const map = new Map({
      layers: [
        new TileLayer({
          source: new OSM(),
        }),
        new LayerGroup({
          layers: [
            new TileLayer({
              source: new TileJSON({
                url:
                  'https://api.tiles.mapbox.com/v4/mapbox.20110804-hoa-foodinsecurity-3month.json?secure&access_token=' +
                  key,
                crossOrigin: 'anonymous',
              }),
            }),
            new TileLayer({
              source: new TileJSON({
                url:
                  'https://api.tiles.mapbox.com/v4/mapbox.world-borders-light.json?secure&access_token=' +
                  key,
                crossOrigin: 'anonymous',
              }),
            }),
          ],
        }),
      ],
      target: 'map',
      view: new View({
        center: fromLonLat([37.4057, 8.81566]),
        zoom: 4,
      }),
    });

    function bindInputs(layerid, layer) {
      const visibilityInput = document.querySelector(layerid + ' input.visible');
      visibilityInput.addEventListener('change', function () {
        layer.setVisible(this.checked);
      });
      visibilityInput.addEventListener('change', function () {
        layer.setVisible(this.checked);
      });
      visibilityInput.checked = layer.getVisible();

      const opacityInput = document.querySelector(layerid + ' input.opacity');
      opacityInput.addEventListener('input', function () {
        layer.setOpacity(parseFloat(this.value));
      });
      opacityInput.value = String(layer.getOpacity());
    }
    function setup(id, group) {
      group.getLayers().forEach(function (layer, i) {
        const layerid = id + i;
        bindInputs(layerid, layer);
        if (layer instanceof LayerGroup) {
          setup(layerid, layer);
        }
      });
    }
    setup('#layer', map.getLayerGroup());

    document.querySelectorAll('#layertree li > span').forEach(function (element) {
      element.addEventListener('click', function () {
        this.parentNode.querySelector('fieldset').style.display =
          this.parentNode.querySelector('fieldset').style.display === 'none'
            ? ''
            : 'none';
      });
      element.parentNode.querySelector('fieldset').style.display = 'none';
    });

##### index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Layer Groups</title>
        <link rel="stylesheet" href="node_modules/ol/ol.css">
        <style>
          .map {
            width: 100%;
            height: 400px;
          }
          #layertree li > span {
            cursor: pointer;
          }
          #layertree label {
            display: block;
          }
        </style>
      </head>
      <body>
        <div id="map" class="map"></div>
        <div id="layertree">
          <h5>Click on layer nodes below to change their properties.</h5>
          <ul>
            <li><span>OSM layer</span>
              <fieldset id="layer0">
                <label class="checkbox" for="visible0">
                  visible <input id="visible0" class="visible" type="checkbox"/>
                </label>
                <label>
                  opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
                </label>
              </fieldset>
            </li>
            <li>
              <span>Layer group</span>
              <fieldset id="layer1">
                <label class="checkbox" for="visible1">
                  visible <input id="visible1" class="visible" type="checkbox"/>
                </label>
                <label>
                  opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
                </label>
              </fieldset>
              <ul>
                <li>
                  <span>Food insecurity layer</span>
                  <fieldset id="layer10">
                    <label class="checkbox" for="visible10">
                      visible <input id="visible10" class="visible" type="checkbox"/>
                    </label>
                    <label>
                      opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
                    </label>
                  </fieldset>
                </li>
                <li>
                  <span>World borders layer</span>
                  <fieldset id="layer11">
                    <label class="checkbox" for="visible11">
                      visible <input id="visible11" class="visible" type="checkbox"/>
                    </label>
                    <label>
                      opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
                    </label>
                  </fieldset>
                </li>
              </ul>
            </li>
          </ul>
        </div>

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

##### package.json

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