JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>
<!--
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
-->
<html>
<head>

    <meta charset="utf-8">
    <meta name="description" content="WebRTC code samples">
    <meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
    <meta itemprop="description" content="Client-side WebRTC code samples">
    <meta itemprop="name" content="WebRTC code samples">
    <meta name="mobile-web-app-capable" content="yes">
    <meta id="theme-color" name="theme-color" content="#ffffff">

    <base target="_blank">

    <title>MediaStream Recording</title>

    <link href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css">

</head>

<body>

<div id="container">

    <h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a>
        <span>MediaRecorder</span></h1>

    <p>For more information see the MediaStream Recording API <a
            href="http://w3c.github.io/mediacapture-record/MediaRecorder.html"
            title="W3C MediaStream Recording API Editor's Draft">Editor's&nbsp;Draft</a>.</p>

    <video id="gum" playsinline autoplay muted></video>

    <div>
        <button id="start">Start camera</button>
        <button id="record" disabled>Start Recording</button>
        <button id="play" disabled>Play</button>
        <button id="download" disabled>Download</button>
    </div>

    <div>
        <span id="errorMsg"></span>
    </div>

    <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/getusermedia/record"
       title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>

</div>

<!-- include adapter for srcObject shim -->
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

</body>
</html>

CSS

/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 .hidden {
  display: none;
}

.highlight {
  background-color: #eee;
  font-size: 1.2em;
  margin: 0 0 30px 0;
  padding: 0.2em 1.5em;
}

.warning {
  color: red;
  font-weight: 400;
}

@media screen and (min-width: 1000px) {
  /* hack! to detect non-touch devices */
  div#links a {
    line-height: 0.8em;
  }
}

audio {
  max-width: 100%;
}

body {
  font-family: 'Roboto', sans-serif;
  font-weight: 300;
  margin: 0;
  padding: 1em;
  word-break: break-word;
}

button {
  background-color: #d84a38;
  border: none;
  border-radius: 2px;
  color: white;
  font-family: 'Roboto', sans-serif;
  font-size: 0.8em;
  margin: 0 0 1em 0;
  padding: 0.5em 0.7em 0.6em 0.7em;
}

button:active {
  background-color: #cf402f;
}

button:hover {
  background-color: #cf402f;
}

button[disabled] {
  color: #ccc;
}

button[disabled]:hover {
  background-color: #d84a38;
}

canvas {
  background-color: #ccc;
  max-width: 100%;
  width: 100%;
}

code {
  font-family: 'Roboto', sans-serif;
  font-weight: 400;
}

div#container {
  margin: 0 auto 0 auto;
  max-width: 60em;
  padding: 1em 1.5em 1.3em 1.5em;
}

div#links {
  padding: 0.5em 0 0 0;
}

h1 {
  border-bottom: 1px solid #ccc;
  font-family: 'Roboto', sans-serif;
  font-weight: 500;
  margin: 0 0 0.8em 0;
  padding: 0 0 0.2em 0;
}

h2 {
  color: #444;
  font-weight: 500;
}

h3 {
  border-top: 1px solid #eee;
  color: #666;
  font-weight: 500;
  margin: 10px 0 10px 0;
  white-space: nowrap;
}

li {
  margin: 0 0 0.4em 0;
}

html {
  /* avoid annoying page width change
  when moving from the home page */
  overflow-y: scroll;
}

img {
  border: none;
  max-width: 100%;
}

input[type=radio] {
  position: relative;
  top: -1px;
}

p {
  color: #444;
  font-weight: 300;
}

p#data {
  border-top: 1px dotted #666;
 ...

JavaScript

/*
*  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
*  Use of this source code is governed by a BSD-style license
*  that can be found in the LICENSE file in the root of the source
*  tree.
*/

// This code is adapted from
// https://rawgit.com/Miguelao/demos/master/mediarecorder.html

'use strict';

/* globals MediaRecorder */

let mediaRecorder;
let recordedBlobs;

const errorMsgElement = document.querySelector('span#errorMsg');
const gumVideo = document.querySelector('video#gum');
const recordButton = document.querySelector('button#record');

recordButton.addEventListener('click', () => {
  if (recordButton.textContent === 'Start Recording') {
    startRecording();
  } else {
    stopRecording();
    recordButton.textContent = 'Start Recording';
    playButton.disabled = false;
    downloadButton.disabled = false;
  }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
  const superBuffer = new Blob(recordedBlobs, {type: mediaRecorder.mimeType});
  gumVideo.src = null;
  gumVideo.srcObject = null;
  gumVideo.src = window.URL.createObjectURL(superBuffer);
  gumVideo.controls = true;
  gumVideo.play();
});

const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
  const blob = new Blob(recordedBlobs, {type: mediaRecorder.mimeType});
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.style.display = 'none';
  a.href = url;
  a.download = 'test.webm';
  document.body.appendChild(a);
  a.click();
  setTimeout(() => {
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  }, 100);
});

function handleDataAvailable(event) {
  console.log('handleDataAvailable', event);
  if (event.data && event.data.size > 0) {
    recordedBlobs.push(event.data);
  }
}

function startRecording() {
  recordedBlobs = [];
  let options = {mimeType: 'video/webm;codecs=vp9,opus'};
  if...