DEV Community

Cover image for Build a Simple Screen Recorder with HTML, CSS, and JavaScript
George Alex
George Alex

Posted on • Edited on

1

Build a Simple Screen Recorder with HTML, CSS, and JavaScript

Welcome everyone to this simple and easy screen recording project that we are going to be working on together, using just plain old HTML, CSS and some JavaScript. You may wonder why someone would need something like this. The answer is that capturing screen activity is essential for tutorials, presentations, bug reporting and many more. Whether you are looking to create a step-by-step video for your channel or looking to send your impressive portfolio to a potential client, you may need something like this app. In the following post I’ll walk you through a minimal yet powerful screen recorder, built entirely with HTML, CSS, and JavaScript.

Tools

Now, like I said earlier, we will not be using any libraries, however if you have no coding experience, I highly recommend this tutorial here, on how to get started with code editors.

What are we actually going to build?

This project allows the user to record their device screen along with complete audio track directly from their preferred browser. When you press the record button, you will be prompted to select what element you like to record, such as a browser tab (Chrome in my case), if you have multiple apps or windows, it will prompt you to choose one, or you can simply choose to record the entire screen. In the bottom right corner, you also have the ‘Also share with audio’ option which you can enable or disable at your convenience. A countdown timer precedes the recording, and the final video is available to download in WebM format.

The code is lightweight, requiring no external libraries, and takes advantage of native browser APIs.
Let’s take a closer look.

Breakdown

  • HTML structures the interface, including a video preview, a record button, and a download link.
  • CSS styles the layout, adds responsiveness, and creates an engaging countdown overlay.
  • JavaScript handles screen capture, video recording, and download logic.

Great, now let’s dive into the code and see how it works.

HTML Structure

First you will need to create an index.html file, in which we will write, you guessed it, the HTML code that will provide the very basic UI. Again, if you have previous experience with coding, feel free to modify it to suit the needs of your own project, if you have no coding experience just go ahead copy the code below as is.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <script src="script.js" defer></script>
    <title>Screen Recorder</title>
  </head>
  <body>
    <div class="countdown" id="countdown"></div>

    <div class="screen-recorder">
      <h1>Capture your media screen</h1>
      <video controls preload="none" id="video"></video>

      <nav>
        <button type="button" class="btn" id="btn" aria-label="Start recording">Record</button>
        <a href="#" class="btn" id="link" aria-label="Download recorded video" download="recording.webm">Download Video</a>
      </nav>
    </div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

The video element displays the recorded screen, while the button and the a elements allow for the recording process to begin and later for download.

CSS Styling

Next, we will be taking a look at how we can make our project more visually appealing and just like we did with the index.html file, we will also need to create a style.css. For those that are unfamiliar with CSS, you can find a great deal of free lessons here.

Now let’s take a closer look at the CSS:

  • Global Reset: * applies padding, margin reset, and box-sizing: border-box globally to ensure consistent spacing across elements.
  • Body Centering: The body uses display: grid and place-items: center to center everything vertically and horizontally.
  • Countdown Overlay: The .countdown class is hidden by default (visibility: hidden) and appears as a Fullscreen overlay during countdown. The font-size: 10rem makes the countdown digits large and visible.
  • Screen Recorder Layout: .screen-recorder centers its content using flexbox, aligns items in a column, and adds spacing between elements with gap: 2rem.
  • Responsive Video: The video element scales responsively, adjusting based on the screen size, thanks to the width: 100% and max-width constraints.
  • Buttons: .btn provides a consistent look for buttons with a blue background, white text, and hover effect (background-color: #357ec7).
  • Responsive Design: The @media query ensures the layout and font sizes adapt on screens smaller than 768px, making the app mobile-friendly.

If you are unfamiliar with CSS media queries, you can find a great deal of information and free tutorials here.

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

body {
  width: 100vw;
  min-height: 100vh;
  display: grid;
  place-items: center;
  background-color: #f4f4f4;
}

.countdown {
  visibility: hidden;
  color: green;
  font-size: 10rem;
  font-weight: 900;
  background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent black background */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.screen-recorder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rem;
  width: 90%;
  max-width: 1000px;
  padding: 2rem;
  background-color: #fff;
  color: #202020;
  border-radius: 10px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
}

.screen-recorder video {
  width: 100%;
  max-width: 782px;
  aspect-ratio: 16 / 9;
  max-height: 440px;
  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1), -2px -2px 5px rgba(0, 0, 0, 0.1);
  border-radius: 10px;
  display: none;
}

h1 {
  text-transform: capitalize;
  font-size: 3rem;
  font-weight: bold;
  color: #202020;
}

.btn {
  background-color: #428bca;
  color: #fff;
  font-weight: 900;
  padding: 0.75rem 1.5rem;
  border-radius: 0.5rem;
  cursor: pointer;
  text-transform: capitalize;
  border: 1px solid #428bca;
  transition: background-color 0.3s ease, color 0.3s ease;
}

.btn:hover,
.btn:focus {
  background-color: #357ec7;
  outline: 2px solid #357ec7;
  outline-offset: 2px;
}

a {
  text-decoration: none;
  margin-inline-start: 20px;
  display: none;
}

@media (max-width: 768px) {
  .screen-recorder video {
      width: 100%;
      height: auto;
  }

  h1 {
      font-size: 2.5rem;
  }

  .btn {
      padding: 0.5rem 1rem;
      font-size: 1rem;
  }

  .countdown {
      font-size: 6rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

All of the above code ensures a minimal and user-friendly interface, again for those of you that are more experienced, feel free to modify the code as you see fit.

JavaScript Functionality

In the previous chapters we’ve looked at the HTML and CSS code, now it’s time to take a closer look at the brain of our app, the JavaScript code.

As before, you will need to create a script.js file in which our main JavaScript logic will reside. Again, if you are new to this, just copy and paste the below code into your script.js file.

const startBtn = document.getElementById("btn");
const downloadLink = document.getElementById("link");
const videoElement = document.getElementById("video");
const countdownElement = document.getElementById("countdown");

let blob = null,
    videoStream = null,
    audioStream = null;

startBtn.addEventListener("click", startScreenCapturing);

async function startScreenCapturing() {
    if (!navigator.mediaDevices.getDisplayMedia) {
        alert("Screen capturing is not supported in your browser.");
        return;
    }

    if (videoStream) {
        videoStream.getTracks().forEach(track => track.stop());
    }
    if (audioStream) {
        audioStream.getTracks().forEach(track => track.stop());
    }

    try {
        videoStream = await navigator.mediaDevices.getDisplayMedia({
            video: true,
            audio: true,
        });

        try {
            audioStream = await navigator.mediaDevices.getUserMedia({
                audio: {
                    echoCancellation: true,
                    noiseSuppression: true,
                    sampleRate: 44100,
                },
            });
            const audioTrack = audioStream.getTracks()[0];
            videoStream.addTrack(audioTrack);
        } catch (error) {
            console.warn("No audio stream available:", error);
        }

        startBtn.textContent = "Recording...";
        startBtn.disabled = true;

        await recordStream(videoStream);
    } catch (error) {
        console.error("Screen capture failed:", error);
        startBtn.textContent = "Record";
        startBtn.disabled = false;
    }
}

function countdown(seconds = 3) {
    return new Promise((resolve) => {
        let counter = seconds;
        countdownElement.style.visibility = "visible";
        countdownElement.textContent = counter;
        const interval = setInterval(() => {
            counter--;
            countdownElement.textContent = counter; 
            if (counter < 0) {
                clearInterval(interval);
                countdownElement.style.visibility = "hidden";
                resolve();
            }
        }, 1000);
    });
}

function showRecordedVideo() {
    if (!blob) {
        console.error("No recorded video available.");
        return;
    }

    if (videoElement.src) {
        URL.revokeObjectURL(videoElement.src);
    }

    videoElement.src = URL.createObjectURL(blob);
    videoElement.style.display = "block";

    downloadLink.href = videoElement.src;
    downloadLink.download = "screen-recording.webm";
    downloadLink.style.display = "inline-block";

    startBtn.textContent = "Record";
    startBtn.disabled = false;
}

async function recordStream(stream) {
    await countdown();

    const supportedMimeType = MediaRecorder.isTypeSupported("video/webm; codecs=vp8,opus")
        ? "video/webm; codecs=vp8,opus"
        : "video/webm";
    const mediaRecorder = new MediaRecorder(stream, {
        mimeType: supportedMimeType,
    });
    const recordedChunks = [];

    mediaRecorder.addEventListener("dataavailable", (e) => recordedChunks.push(e.data));

    const videoTrack = stream.getVideoTracks()[0];
    if (videoTrack) {
        videoTrack.addEventListener("ended", () => mediaRecorder.stop());
    }

    mediaRecorder.addEventListener("stop", () => {
        if (recordedChunks.length === 0) {
            console.error("No recorded video available.");
            return;
        }

        blob = new Blob(recordedChunks, { type: recordedChunks[0].type });
        showRecordedVideo();
    });

    mediaRecorder.start();
}
Enter fullscreen mode Exit fullscreen mode

How the JavaScript Works

  • Event Listener: We begin by placing event listeners so when the user clicks the record button, the startScreenCapturing function is triggered.
  • Screen and Audio Capture: The function checks if screen recording is supported by your browser. If so, it will request screen and audio permissions.
  • Recording Process: After the user grants permission, the screen and audio streams are combined and recorded.
  • Countdown Timer: A short countdown occurs before recording begins, giving users time to prepare.
  • Stopping and Downloading: After the recording stops, the video is saved as a downloadable file accessible via the download link.

Frequently Asked Questions (FAQ)

Q: Can this screen recorder capture audio from the system?

  • Yes, this project captures audio from both the system and the user's microphone. However, there are some browser limitations when it comes to capturing system audio due to security policies. So, check if your browser allows you to do this.

Q: Why can't I record my screen?

  • If screen capturing isn't working, ensure your browser supports navigator.mediaDevices.getDisplayMedia(). Some older browsers may not support this API.

Q: What format is the video saved in?

  • The video is saved in WebM format, which is widely supported by many modern browsers. You can convert it to MP4 or any other formats using various online tools.

Q: How do I improve the audio quality?

  • The script requests audio with echo cancellation and noise suppression. Using an external microphone is recommended for better results.

Q: Can I pause the recording?

  • Currently, there is no pause functionality. However, you can stop the recording and start a new one immediately.

Q: How large can the recorded files get?

  • The file size depends on the length and quality of the recording. Short videos are typically small, but longer recordings may require more storage space.

Pros and Cons

Pros Cons
Lightweight, no external libraries Limited to modern browsers
Simple to implement and understand No advanced editing features
Combines video and audio recording Audio may not work on all devices
Downloadable video in WebM format File format may need conversion for sharing
Responsive design No real-time video preview during recording

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

While many AI coding tools operate as simple command-response systems, Qodo Gen 1.0 represents the next generation: autonomous, multi-step problem-solving agents that work alongside you.

Read full post →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay