Build 30 minutes Countdown Timer in JavaScript with Alarm sound

In this article, we will learn how to create 30 minutes countdown timer where you can start a countdown, stop the countdown and also reset the countdown to the default value. In addition, we will add an alarm sound when the countdown reaches 0 after successfully completing 30 minutes.

30 min countdown timer
30-min countdown timer with start, stop and reset

1. Create a <span></span> container for every Digit

The first step is to create HTML <span></span> element for every digit that needs to be display in the countdown clock. For 30 minutes countdown, we need 4 digits with 2 each to display minutes and seconds remaining in the countdown. Additionally, we also add a “:” separator to divide minutes and seconds timing.

<div>
   <span class="count-digit">3</span>
   <span class="count-digit">0</span>
   <span class="separator">:</span>
   <span class="count-digit">0</span>
   <span class="count-digit">0</span>
</div>

2. Add buttons for start, stop and reset actions

Once we are displaying the minutes and seconds of the count, now we will add HTML buttons for the start, stop and reset actions of the timer. For CSS code for timer and buttons please refer “Final solution code” section at the end of this article.

<div class="options">
   <button id="stop-timer">
     <img src="https://img.icons8.com/ios-glyphs/30/000000/pause--v1.png" />
   </button>
   <button id="start-timer">
     <img src="https://img.icons8.com/ios-glyphs/30/000000/play--v1.png" />
   </button>
   <button id="reset-timer">
     <img src="https://img.icons8.com/ios-glyphs/30/000000/stop.png" />
   </button>
</div>
30 min countdown timer preview
30-min Countdown timer with HTML and CSS code

3. Function to Generate countdown string

Before we add any JavaScript functionality to the app, we need to create JavaScript functions to support countdown timer functionalities. Creating separate functions allows for the reuse of the code and makes it easier to modify/add existing functionalities.

First, we will create a function to generate the countdown string which requires remaining time in seconds. Displaying the countdown directly in seconds is less readable, hence will generate the countdown string in “MM:SS” format and append zeros for single-digit values.

// Default inital value of timer
const defaultValue = 30 * 60;

// variable to the time
var countDownTime = defaultValue;

// Function calculate time string
const findTimeString = () => {
  var minutes = String(Math.trunc(countDownTime / 60));
  var seconds = String(countDownTime % 60);
  if (minutes.length === 1) {
    minutes = "0" + minutes;
  }
  if (seconds.length === 1) {
    seconds = "0" + seconds;
  }
  return minutes + seconds;
};

4. Function to Update and Display countdown

Once we are able to generate the string in “MM:SS” format, now we have to display the string on the screen. We select every <span></span> containers created in step 1 using “querySelectorAll” method and iterate over the list and assigning the DOM innerHTML with the characters of the countdown string.

// Select Every Count Container
const countContainer = document.querySelectorAll(".count-digit");

// Function to display coundown on screen
const renderTime = () => {
  const time = findTimeString();
  countContainer.forEach((count, index) => {
    count.innerHTML = time.charAt(index);
  });
};

5. Start timer functionality

At the start of the timer countdown, we initialize runCountDown function to run after every second. In the runCountDown method, we decrement the countdown time and display it on the screen. Additionally, on timeout, the countdown is stopped by using clearInterval(), and the countDownTime is set to the default value.

const startAction = document.getElementById("start-timer");

// Function to start Countdown
const startTimer = () => {
  if (isStopped) {
    isStopped = false;
    timerID = setInterval(runCountDown, 500);
  }
};

startAction.onclick = startTimer;

// function to execute timer
const runCountDown = () => {
  // decrement time
  countDownTime -= 1;
  //Display updated time
  renderTime();

  // timeout on zero
  if (countDownTime === 0) {
    stopTimer();
    countDownTime = defaultValue;
  }
};

6. Stop timer functionality

For stopping the timer, we just need to perform clearInterval() with the timeID retrieved earlier from setInterval() in start timer functionality.

const stopAction = document.getElementById("stop-timer");

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

stopAction.onclick = stopTimer;

7. Reset timer functionality

To reset the timer, in addition to stopping the timer, we need to reset the countDownTime value and display the updated value on the screen.

const resetAction = document.getElementById("reset-timer");

// Function to reset Countdown
const resetTimer = () => {
  stopTimer();
  countDownTime = defaultValue;
  renderTime();
};

resetAction.onclick = resetTimer;

8. Trigger Alarm sound on timeout

The final step is to include an HTML5 audio tag and initialize the audio file with the URL. Then we will trigger that audio file using play() on timeout.

<audio id="alarm_audio"></audio>
// Select HTML5 Audio element
const timeoutAudio = document.getElementById("alarm_audio");

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

// Updated countdown function with alarm trigger
const runCountDown = () => {
  countDownTime -= 1;
  renderTime();

  // timeout on zero
  if (countDownTime === 0) {
    stopTimer();
    // Play alarm on timeout
    timeoutAudio.play();
    countDownTime = defaultValue;
  }
};

Final Solution Code

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>30 min countdown timer</title>
    <script src="main.js" defer></script>
  </head>
  <body>
    <h1>CountDown Timer</h1>
    <div>
      <span class="count-digit">3</span>
      <span class="count-digit">0</span>
      <span class="separator">:</span>
      <span class="count-digit">0</span>
      <span class="count-digit">0</span>
    </div>
    <div class="options">
      <button id="stop-timer">
        <img src="https://img.icons8.com/ios-glyphs/30/000000/pause--v1.png" />
      </button>
      <button id="start-timer">
        <img src="https://img.icons8.com/ios-glyphs/30/000000/play--v1.png" />
      </button>
      <button id="reset-timer">
        <img src="https://img.icons8.com/ios-glyphs/30/000000/stop.png" />
      </button>
    </div>
    <audio id="alarm_audio"></audio>
  </body>
</html>

styles.css

body {
  font-family: monaco;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
h1 {
  margin-bottom: 50px;
}
.count-digit {
  color: #ffffff;
  background-color: #333;
  font-size: 56px;
  padding: 10px 20px;
  text-shadow: 0 1px 0 white;
  border-radius: 10%;
}
.separator {
  font-size: 56px;
}
.options {
  margin-top: 50px;
  display: flex;
  gap: 30px;
}

main.js

import "./styles.css";

// Select Every Count Container
const countContainer = document.querySelectorAll(".count-digit");

// Select option buttons
const startAction = document.getElementById("start-timer");
const stopAction = document.getElementById("stop-timer");
const resetAction = document.getElementById("reset-timer");

// Select HTML5 Audio element
const timeoutAudio = document.getElementById("alarm_audio");

// Default inital value of timer
const defaultValue = 30 * 60;

// variable to the time
var countDownTime = defaultValue;

// variable to store time interval
var timerID;

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

// Function calculate time string
const findTimeString = () => {
  var minutes = String(Math.trunc(countDownTime / 60));
  var seconds = String(countDownTime % 60);
  if (minutes.length === 1) {
    minutes = "0" + minutes;
  }
  if (seconds.length === 1) {
    seconds = "0" + seconds;
  }
  return minutes + seconds;
};

// Function to start Countdown
const startTimer = () => {
  if (isStopped) {
    isStopped = false;
    timerID = setInterval(runCountDown, 500);
  }
};

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

// Function to reset Countdown
const resetTimer = () => {
  stopTimer();
  countDownTime = defaultValue;
  renderTime();
};

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

// Attach onclick event to buttons
startAction.onclick = startTimer;
resetAction.onclick = resetTimer;
stopAction.onclick = stopTimer;

// Function to display coundown on screen
const renderTime = () => {
  const time = findTimeString();
  countContainer.forEach((count, index) => {
    count.innerHTML = time.charAt(index);
  });
};

// function to execute timer
const runCountDown = () => {
  // decement time
  countDownTime -= 1;
  //Display updated time
  renderTime();

  // timeout on zero
  if (countDownTime === 0) {
    stopTimer();
    // Play alarm on timeout
    timeoutAudio.play();
    countDownTime = defaultValue;
  }
};