# Related content

Show related videos inside the player and load them in place when the viewer picks one.

## Open Video UI

Tip: open your browser's developer console and use the `player` and `THEOplayer` variables to interact with this demo.

Open Video UI has no built-in related-content overlay, so this example fills a `theoplayer-menu` with a grid of tiles. Each tile loads its source directly in the player, and the menu opens automatically when the video ends.

```js
tile.addEventListener('click', () => {
  relatedMenu.closeMenu();
  player.autoplay = true;
  player.source = {
    sources: { src: item.source, type: 'application/x-mpegurl' },
    poster: item.image,
    metadata: { title: item.title },
  };
});

player.addEventListener('ended', () => {
  if (relatedMenu.hasAttribute('hidden')) {
    relatedButton.click();
  }
});
```

Code

demo.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Related content</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet" />
    <style>
      html,
      body {
        margin: 0;
        padding: 0;
      }

      theoplayer-default-ui:not(:defined) {
        display: inline-block;
        box-sizing: border-box;
      }

      theoplayer-default-ui {
        width: 100%;
        aspect-ratio: 16 / 9;
        font-family: 'Noto Sans', sans-serif;
        background: #000;
      }

      #related-menu {
        box-sizing: border-box;
        max-width: min(34rem, calc(100vw - 2rem));
        padding: 1rem;
        color: #fff;
      }

      #related-menu [slot='heading'] {
        font-weight: 700;
      }

      .related-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
        gap: 0.75rem;
        margin-top: 0.75rem;
      }

      .related-tile {
        padding: 0;
        border: 0;
        border-radius: 0.4rem;
        overflow: hidden;
        background: rgb(255 255 255 / 8%);
        color: #fff;
        font: inherit;
        text-align: left;
        cursor: pointer;
      }

      .related-tile:hover,
      .related-tile:focus-visible {
        background: rgb(255 255 255 / 18%);
      }

      .related-tile img {
        display: block;
        width: 100%;
        aspect-ratio: 16 / 9;
        object-fit: cover;
      }

      .related-tile span {
        display: block;
        padding: 0.4rem 0.5rem;
      }

      .related-tile .related-duration {
        padding-top: 0;
        font-size: 0.8rem;
        opacity: 0.75;
      }

      .related-icon {
        width: 1.25rem;
        height: 1.25rem;
        vertical-align: middle;
      }
    </style>
    <script src="https://cdn.theoplayer.com/dash/theoplayer/THEOplayer.js"></script>
    <script nomodule src="https://unpkg.com/@theoplayer/web-ui@2/polyfills"></script>
    <script async src="https://unpkg.com/@theoplayer/web-ui@2"></script>
  </head>
  <body>
    <!--
      libraryLocation: For demonstration purposes, we use the THEOplayer CDN.
      For production use, host the library yourself and update this URL and the script above.

      licenseUrl: Point this to your license file, or replace it with a license property.
    -->
    <theoplayer-default-ui
      id="player-ui"
      configuration='{"libraryLocation":"https://cdn.theoplayer.com/dash/theoplayer/","licenseUrl":"../../../../theoplayer-license.txt","mutedAutoplay":"all"}'
      source='{"sources":{"src":"https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny.m3u8","type":"application/x-mpegurl"},"poster":"https://cdn.theoplayer.com/video/big_buck_bunny/poster.jpg","metadata":{"title":"Big Buck Bunny"}}'
    >
      <theoplayer-menu-button slot="bottom-control-bar" menu="related-menu" aria-label="Related content">
        <svg class="related-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
          <rect x="3" y="3" width="7" height="7" rx="1" />
          <rect x="14" y="3" width="7" height="7" rx="1" />
          <rect x="3" y="14" width="7" height="7" rx="1" />
          <rect x="14" y="14" width="7" height="7" rx="1" />
        </svg>
      </theoplayer-menu-button>
      <theoplayer-menu id="related-menu" slot="menu" hidden>
        <span slot="heading">Related content</span>
        <div class="related-grid" id="related-grid"></div>
      </theoplayer-menu>
    </theoplayer-default-ui>
    <script src="../utils.js"></script>
    <script>
      const relatedMenu = document.querySelector('#related-menu');
      const relatedButton = document.querySelector('theoplayer-menu-button[menu="related-menu"]');
      const relatedGrid = document.querySelector('#related-grid');

      const relatedItems = [
        {
          title: 'Tears of Steel',
          duration: '12:14',
          image: 'https://cdn.theoplayer.com/video/tears_of_steel/poster.jpg',
          source: 'https://cdn.theoplayer.com/video/tears_of_steel/index.m3u8',
        },
        {
          title: 'Star Wars',
          duration: '3:31',
          image: 'https://cdn.theoplayer.com/video/star_wars_episode_vii-the_force_awakens_official_comic-con_2015_reel_(2015)/poster.jpg',
          source: 'https://cdn.theoplayer.com/video/star_wars_episode_vii-the_force_awakens_official_comic-con_2015_reel_(2015)/index.m3u8',
        },
        {
          title: 'Big Buck Bunny',
          duration: '9:56',
          image: 'https://cdn.theoplayer.com/video/big_buck_bunny/poster-alt1.jpg',
          source: 'https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny_metadata.m3u8',
        },
      ];

      onPlayerReady((player) => {
        for (const item of relatedItems) {
          const tile = document.createElement('button');
          tile.className = 'related-tile';
          tile.type = 'button';
          const image = document.createElement('img');
          image.src = item.image;
          image.alt = '';
          tile.appendChild(image);
          const title = document.createElement('span');
          title.textContent = item.title;
          tile.appendChild(title);
          const duration = document.createElement('span');
          duration.className = 'related-duration';
          duration.textContent = item.duration;
          tile.appendChild(duration);
          tile.addEventListener('click', () => {
            relatedMenu.closeMenu();
            player.autoplay = true;
            player.source = {
              sources: { src: item.source, type: 'application/x-mpegurl' },
              poster: item.image,
              metadata: { title: item.title },
            };
          });
          relatedGrid.appendChild(tile);
        }

        player.addEventListener('ended', () => {
          if (relatedMenu.hasAttribute('hidden')) {
            relatedButton.click();
          }
        });
      });
    </script>
  </body>
</html>
```

## Default UI

The [Default UI](https://optiview.dolby.com/docs/theoplayer/ui/web/default-ui.md) has a built-in related-content overlay driven by `player.related.sources`. Each item carries a `source` description, so clicking a tile loads it in the same player.

```js
player.related.sources = [
  {
    image: 'https://cdn.theoplayer.com/video/tears_of_steel/poster.jpg',
    title: 'Tears of Steel',
    duration: '12:14',
    source: {
      sources: [{ src: 'https://cdn.theoplayer.com/video/tears_of_steel/index.m3u8', type: 'application/x-mpegurl' }],
    },
  },
];

player.addEventListener('ended', () => {
  if (!player.related.showing) {
    player.related.show();
  }
});
```

Code

default-ui.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Related content (Default UI)</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdn.theoplayer.com/dash/theoplayer/ui.css" />
    <script src="https://cdn.theoplayer.com/dash/theoplayer/THEOplayer.js"></script>
    <style>
      html,
      body {
        margin: 0;
        padding: 0;
      }

      #player {
        position: relative;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div id="player" class="video-js theoplayer-skin vjs-16-9"></div>
    <script>
      var player = new THEOplayer.Player(document.querySelector('#player'), {
        libraryLocation: 'https://cdn.theoplayer.com/dash/theoplayer/',
        licenseUrl: '../../../../theoplayer-license.txt',
      });
      player.source = {
        sources: [{ src: 'https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny.m3u8', type: 'application/x-mpegurl' }],
        poster: 'https://cdn.theoplayer.com/video/big_buck_bunny/poster.jpg',
        metadata: { title: 'Big Buck Bunny' },
      };

      // Each related item carries its own source description, so clicking a tile loads it in this player.
      player.related.sources = [
        {
          image: 'https://cdn.theoplayer.com/video/tears_of_steel/poster.jpg',
          title: 'Tears of Steel',
          duration: '12:14',
          source: {
            sources: [{ src: 'https://cdn.theoplayer.com/video/tears_of_steel/index.m3u8', type: 'application/x-mpegurl' }],
            poster: 'https://cdn.theoplayer.com/video/tears_of_steel/poster.jpg',
            metadata: { title: 'Tears of Steel' },
          },
        },
        {
          image: 'https://cdn.theoplayer.com/video/star_wars_episode_vii-the_force_awakens_official_comic-con_2015_reel_(2015)/poster.jpg',
          title: 'Star Wars',
          duration: '3:31',
          source: {
            sources: [
              {
                src: 'https://cdn.theoplayer.com/video/star_wars_episode_vii-the_force_awakens_official_comic-con_2015_reel_(2015)/index.m3u8',
                type: 'application/x-mpegurl',
              },
            ],
            poster: 'https://cdn.theoplayer.com/video/star_wars_episode_vii-the_force_awakens_official_comic-con_2015_reel_(2015)/poster.jpg',
            metadata: { title: 'Star Wars' },
          },
        },
        {
          image: 'https://cdn.theoplayer.com/video/big_buck_bunny/poster-alt1.jpg',
          title: 'Big Buck Bunny',
          duration: '9:56',
          source: {
            sources: [{ src: 'https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny_metadata.m3u8', type: 'application/x-mpegurl' }],
            poster: 'https://cdn.theoplayer.com/video/big_buck_bunny/poster-alt1.jpg',
            metadata: { title: 'Big Buck Bunny' },
          },
        },
      ];

      player.addEventListener('ended', function () {
        if (!player.related.showing) {
          player.related.show();
        }
      });
    </script>
  </body>
</html>
```
