Build 30-second Countdown Timer in JavaScript with Sound

In this article, we will learn how to build a 30-second countdown timer with start, stop and reset functionality. Additionally, we will learn how to trigger an alarm sound when the timer stops at the 0th count.

We will discuss the solution for building the 30-second timer in 8 steps along with the required JavaScript, HTML, and CSS code in every step.

1. Create Container for Timer in HTML

First, we need to create a <div></div> container in the index.html file to display the current countdown of the timer. In the below code, “countdown” is the parent container and the child container “countdown-number” encloses the timer count value with 30 as the default value.

<div id="countdown">
   <div id="countdown-number">30</div>
</div>

2. Adding Buttons for Start, Stop and Reset

In order to add JavaScript functionalities to the app, we need to first add HTML elements allowing users to trigger the JS code on the webpage. Hence to support start, stop and reset functionality we are adding 3 buttons with images representing each action.

Further, we can also add CSS code for the counter container, buttons, and background image. For the CSS code, refer “Final Solution code” section at the end of this article.

<button id="stop">
   <img src="https://img.icons8.com/ios-glyphs/30/000000/pause--v1.png" />
</button>
<button id="start">
   <img src="https://img.icons8.com/ios-glyphs/30/000000/play--v1.png" />
</button>
<button id="reset">
   <img src="https://img.icons8.com/ios-glyphs/30/000000/stop.png" />
</button>
count-down-app-webpage
Countdown timer after HTML and CSS is added

3. Variable to track timer count

Once we have the HTML code in place, it is now time to add JS functionality by embedding the main.js file into the webpage. We will create a JavaScript variable to track the value of the current count in the timer.

// variable to store count
var remainingTime = 30;

// Variable to track whether timer is running or not
var isStopped = true;

4. Function to Start Countdown in JS

To implement start functionality in the countdown timer, first, we assign the selected DOM with the countdown HTML container to a variable. Next, we will create “startTimer” JS function which only executes if “isStopped” value is true, to avoid multiple setInterval() calls when the timer is already running.

To display the timer count, we need to assign “countContainer” innerHTML property with the count value, which ensures the inner HTML of the selected DOM element contains the timer count value.

By using setInterval() ensures renderTime() function is executed every 1 second. The renderTimer() function ensures that “remainingTime” variable is decremented and displayed on screen.

In the case of timeout, the setInterval() timer is cleared, and the “remainingTime” is reset to 30.

// Select Countdown container
const countContainer = document.getElementById("countdown-number");

// function to display time
const renderTime = () => {
  // decement time
  remainingTime -= 1;
  // render count on the screen
  countContainer.innerHTML = remainingTime;
  // timeout on zero
  if (remainingTime === 0) {
    isStopped = true;
    clearInterval(timer);
    remainingTime = 30;
  }
};

// Function to start Timer
const startTimer = () => {
  if (isStopped) {
    isStopped = false;
    countContainer.innerHTML = remainingTime;
    timer = setInterval(renderTime, 1000);
  }
};

5. Function to Stop Countdown in JS

We define stopTimer() function which performs pause functionality for the timer by using clearInterval() on the timer variable which has the id of the timer triggered earlier by setInterval() call.

// Function to stop Timer
const stopTimer = () => {
  isStopped = true;
  if (timer) {
    clearInterval(timer);
  }
};

6. Function to Reset Countdown in JS

For the reset funtionality, in addition to clearInterval(), we need to reassign the “remainingTime” variable with the 30 default value and display it on screen using “countContainer.innerHTML”.

// Function to reset Timer
const resetTimer = () => {
  isStopped = true;
  clearInterval(timer);
  remainingTime = 30;
  countContainer.innerHTML = remainingTime;
};

7. Assigning function as onclick() event for button

The countdown timer is non-functional for the user despite having implemented all JavaScript functionality along with HTML + CSS webpage.

In order to make timer operations, we need to allow users to trigger functionalities from the screen. We accomplish that by assigning the Button DOM element with the respective JavaScript function.

In the below code we assign the start button with startTimer(), reset button with resetTimer, and stop button with stopTime. Learn more about JavaScript events from javatpoint.com/javascript-events.

// Select action buttons
const startButton = document.getElementById("start");
const stopButton = document.getElementById("stop");
const resetButton = document.getElementById("reset");

// Attach onclick event to buttons
startButton.onclick = startTimer;
resetButton.onclick = resetTimer;
stopButton.onclick = stopTimer;

8. Adding alarm sound on timeout

In the final step to make the countdown timer imitate a real timer, we will be adding an alarm sound on timeout.

First, we need to add a <audio></audio> HTML 5 tag to index.html, even though it doesn’t add anything on the screen, it enables javascript to embed an audio file.

<audio id="timeout_audio"></audio>

Once we have the HTML5 audio element, we need to load the audio file using JavaScript code. It is accomplished by selecting the audio HTML5 element using JS DOM selector before assigning the source URL of the audio file and loading it.

Next in renderTime() function, we play the audio file using play() on audio HTML5 element on timeout. Read more about HTML5 Audio tag from developer.mozilla.org/HTML/Element/audio.

// Select timeout Audio element
const timeoutAudio = document.getElementById("timeout_audio");

// Initialize timeout sound
timeoutAudio.src = "http://soundbible.com/grab.php?id=1252&type=mp3";
timeoutAudio.load();

// Update render Time with alarm audio on timeout
const renderTime = () => {
  remainingTime -= 1;
  countContainer.innerHTML = remainingTime;
  // timeout on zero
  if (remainingTime === 0) {
    isStopped = true;
    clearInterval(timer);
    // Play audio on timeout
    timeoutAudio.play();
    remainingTime = 30;
  }
};

Final Solution Code

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>30 second countdown timer</title>
    <script src="main.js" defer></script>
  </head>
  <body>
    <div id="countdown">
      <div id="countdown-number">30</div>
    </div>
    <div class="action-list">
      <button id="stop">
        <img src="https://img.icons8.com/ios-glyphs/30/000000/pause--v1.png" />
      </button>
      <button id="start">
        <img src="https://img.icons8.com/ios-glyphs/30/000000/play--v1.png" />
      </button>
      <button id="reset">
        <img src="https://img.icons8.com/ios-glyphs/30/000000/stop.png" />
      </button>
    </div>
    <audio id="timeout_audio"></audio>
  </body>
</html>

main.js

import "./styles.css";

// Select Countdown container
const countContainer = document.getElementById("countdown-number");

// Select action buttons
const startButton = document.getElementById("start");
const stopButton = document.getElementById("stop");
const resetButton = document.getElementById("reset");

// Select timeout Audio element
const timeoutAudio = document.getElementById("timeout_audio");

// variable to store count
var remainingTime = 30;

// variable to store time interval
var timer;

// Variable to track whether timer is running or not
var isStopped = true;

// Function to start Timer
const startTimer = () => {
  if (isStopped) {
    isStopped = false;
    countContainer.innerHTML = remainingTime;
    timer = setInterval(renderTime, 1000);
  }
};

// Function to stop Timer
const stopTimer = () => {
  isStopped = true;
  if (timer) {
    clearInterval(timer);
  }
};

// Function to reset Timer
const resetTimer = () => {
  isStopped = true;
  clearInterval(timer);
  remainingTime = 30;
  countContainer.innerHTML = remainingTime;
};

// Initialize timeout sound
timeoutAudio.src = "http://soundbible.com/grab.php?id=1252&type=mp3";
timeoutAudio.load();

// Attach onclick event to buttons
startButton.onclick = startTimer;
resetButton.onclick = resetTimer;
stopButton.onclick = stopTimer;

// function to display time
const renderTime = () => {
  // decement time
  remainingTime -= 1;
  // render count on the screen
  countContainer.innerHTML = remainingTime;
  // timeout on zero
  if (remainingTime === 0) {
    isStopped = true;
    clearInterval(timer);
    // Play audio on timeout
    timeoutAudio.play();
    remainingTime = 30;
  }
};

styles.css

body {
  font-family: sans-serif;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-image: url("https://img4.goodfon.com/wallpaper/nbig/1/2e/multfilm-shou-simpsons-personazh-20th-century-fox-art-ris-15.jpg");
}
#countdown {
  display: flex;
  justify-content: center;
  align-items: center;
  color: #0e2c4c;
  font-size: 70px;
  width: 200px;
  height: 200px;
  background-color: #e7d9fc;
  border-radius: 50%;
}
.action-list {
  display: flex;
  gap: 30px;
  margin-top: 30px;
}
button {
  border: none;
  background-color: #e7d9fc;
  border-radius: 50%;
  width: 60px;
  height: 60px;
  cursor: pointer;
}