JSFiddle - React, Tailwind, and code Playground

by Michael Prosser

HTML

<header>
    <h1>Camera fun</h1>
  </header>

  <main>
    <div class="controls">
      <button id="button">Get camera</button>
      <select id="select">
        <option></option>
      </select>
    </div>

    <video id="video" autoplay playsinline></video>
  </main>

  <footer>
    <p>Built by
      <a href="https://twitter.com/philnash">@philnash</a>
    </p>
  </footer>

CSS

html,
body {
  margin: 0;
  padding: 0;
}

html {
  height: 100%;
}

body {
  font-family: Helvetica, Arial, sans-serif;
  min-height: 100%;
  display: grid;
  grid-template-rows: 1fr auto;
}

header {
  background: #f0293e;
  color: #fff;
  text-align: center;
}
main {
  background: #ffffff;
  min-height: 80vh;
}

.controls {
  text-align: center;
  padding: 0.5em 0;
  background: #333e5a;
}

video {
  width: 100%;
  max-width: 600px;
  display: block;
  margin: 0 auto;
}

footer {
  background: #333e5a;
  color: #fff;
  text-align: center;
}

footer a {
  color: #fff;
}

JavaScript

const video = document.getElementById('video');
const button = document.getElementById('button');
const select = document.getElementById('select');
let currentStream;

function stopMediaTracks(stream) {
  stream.getTracks().forEach(track => {
    track.stop();
  });
}

function gotDevices(mediaDevices) {
  select.innerHTML = '';
  select.appendChild(document.createElement('option'));
  let count = 1;
  mediaDevices.forEach(mediaDevice => {
    if (mediaDevice.kind === 'videoinput') {
      const option = document.createElement('option');
      option.value = mediaDevice.deviceId;
      const label = mediaDevice.label || `Camera ${count++}`;
      const textNode = document.createTextNode(label);
      option.appendChild(textNode);
      select.appendChild(option);
    }
  });
}

button.addEventListener('click', event => {
  if (typeof currentStream !== 'undefined') {
    stopMediaTracks(currentStream);
  }
  const videoConstraints = {};
  if (select.value === '') {
    videoConstraints.facingMode = 'environment';
  } else {
    videoConstraints.deviceId = { exact: select.value };
  }
  const constraints = {
    video: videoConstraints,
    audio: false
  };
  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(stream => {
      currentStream = stream;
      video.srcObject = stream;
      return navigator.mediaDevices.enumerateDevices();
    })
    .then(gotDevices)
    .catch(error => {
      console.error(error);
    });
});

navigator.mediaDevices.enumerateDevices().then(gotDevices);