Coding Newbie

How to make a JavaScript Stopwatch

In this tutorial we will make a stopwatch using Vanilla JavaScript. To create a JavaScript Stopwatch, you will need a basic html, CSS and JavaScript knowledge.

Our end result should look like this:

A simple project tutorial that may help you get better understanding over a subject before making a stopwatch is Create a Simple Counter using JavaScript.

Tutorial Structure

If interested, you are more then welcome to go through these lessons first:

Now let’s move on. First, we will create the structure, the HTML part.

HTML

When it comes to HTML, we need to create a simple structure, containing our timer part, and buttons:

<div class="container"> <!-- stopwatch container -->
    <p id="timer"> <!-- timer paragraph -->
        <span id="minutes">00</span> <!-- with span for each timer element -->
        <span>:</span>
        <span id="seconds">00</span>
        <span>:</span>
        <span id="hundreds">00</span>
    </p>
    <div class="btns"> <!-- buttons section -->
         <button id="start" class="btn">Start</button> <!-- start button -->
         <button id="stop" class="btn">Stop</button> <!-- stop button -->
         <button id="restart" class="btn">Restart</button> <!-- restart button -->
    </div>
</div>

CSS

With CSS we will make our stopwatch a little bit more appealing:

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

.container {
    width: 100vw;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

#timer {
    font-size: 4rem;
    background-color: rgb(179, 255, 255);
    padding: 10px;
}

.btns {
    margin-top: 10px;
}

.btn {
    width: 70px;
    height: 30px;
    border: none;
    background-color: rgb(110, 253, 110);
    font-size: 1rem;
    font-weight: bold;
}

.btn:hover {
    cursor: pointer;
    background-color: rgb(255, 115, 0);
    color: white;
}

After writing our HTML and CSS part, we have a structure and layout of our stopwatch. Now comes the most important section, the JavaScript. JavaScript will make our little stopwatch actually work.

JavaScript

First step is to connect our HTML elements with JavaScript code. To this, we will declare variables and store HTML objects, using their IDs.

Declaring Variables

To learn about variables, and different variable alternatives, feel free to read posts:

VAR and LET: All You Must Know About JavaScript Variables

Introducing CONST: New JavaScript Declaration

// timer HTML elements
const minutesEl = document.getElementById('minutes');
const secondsEl = document.getElementById('seconds');
const hundredsEl = document.getElementById('hundreds');

// buttons
const startBtn = document.getElementById('start');
const stopBtn = document.getElementById('stop');
const restartBtn = document.getElementById('restart');

Now when we have our objects stored, we want to make them functional.

Our logic is: when clicked on buttons, our timer elements change.

To achieve this, we need variables for storing the actual timer values, and their values will be forwarded to HTML itself.

// timer values, with 0 as the starting point
let minutes = 0; // for minutes
let seconds = 0; // for seconds
let hundreds = 0; // for hundreds of a second

let time; // variable to store time duration value

After declaring variables, we can move to the next step, which is…

Buttons

We have three buttons: start (startBtn), stop (stopBtn), and restart (restartBtn).

As their names suggest, startBtn will start the timer, stopBtn will stop (pause) it, and restartBtn will restart stopwatch to 0.

However, to make our buttons actually work, we need to “listen” for click event. After JavaScript “hears” a click on the button, it will start function with specified code.

So, let’s add click events to our buttons:

startBtn.addEventListener('click', ()=>{ //this is the arrow function syntax, and ()=>{} is the same as function(){} syntax

})

stopBtn.addEventListener('click', ()=>{

})

restartBtn.addEventListener('click', ()=>{

})

Our buttons are ready for use now, however they do not have any part of code written. Next step is to tell them what to do when we click on them.

Before we continue, you should get familiar with setInterval and clearInterval methods.

The setInterval method repeats executing designated function once for every time interval specified, measured in milliseconds.

The clearInterval stops the time.

You can learn more about these methods at W3Schools.

Let’s tell our buttons what to do when clicked. Because our stopwatch will measure every hundred of a second, for time interval we will use the value 10 (which is 10ms):

startBtn.addEventListener('click', ()=>{
    time = setInterval(countTime,10); //when clicked on start, setInterval method will repeat countTime function every hundred of a second and store that value into
})

stopBtn.addEventListener('click', ()=>{
    clearInterval(time); // stop button will stop the time
})

restartBtn.addEventListener('click', ()=>{
    clearInterval(time); // restart button will stop the time
    hundreds = 0; // and then restore all variable values back to 0
    seconds = 0;
    minutes = 0;
    hundredsEL.innerHTML = "00"; // as well as return html elements inner value back to starting point
    secondsEl.innerHTML = "00";
    minutesEl.innerHTML = "00";
})

Our buttons are ready. However, we do not have a countTime function declared. So, here comes the most important part…

Function countTime

Function countTime will do all the counting of time behind the scenes. Our start button will use setInterval method, and call countTime function every 10ms.

So, with every 10ms passing, we want to add another “hundred”, or to be precise, to increase our hundreds variable, by one. As the time passes, and we accumulate our hundreds, we wish to set rules to convert them into seconds, and then minutes.

In addition, our stopwatch format is 00:00:00. As you can see, we have double digit format for minutes, seconds, and hundreds. With that being said, we must set a rule to append additional 0 to out HTML elements, when our minutes, seconds, or hundreds have a value below 10.

Having considered all the factors, our countTime function will look like this:

function countTime() {
    hundreds++; // start adding hundreds of a second with every function call

    if(hundreds < 10) { // while hundreds count is under 10
        hundredsEl.innerHTML = "0" + hundreds; // we append 0 to hundreds element and add hundreds value
    }
    if(hundreds >= 10) { // when hundreds are equal or greater than 10
        hundredsEl.innerHTML = hundreds; // we display hundreds value
    }
    if(hundreds > 99) { // when hundreds count goes over 99 and reaches 100
        seconds++; // we add 1 second
        hundreds = 0; // restart hundreds
        secondsEl.innerHTML = "0" + seconds; // and display seconds, with 0 appended
    }
    if(seconds > 9) { // when seconds count reaches 10
        secondsEl.innerHTML = seconds; // we display seconds, no need for 0 in front
    }
    if(seconds > 59) { // when seconds reach 60
        minutes++; // we add minute
        seconds = 0; // restart seconds
        hundreds = 0; // restart hundreds
        minutesEl.innerHTML = "0" + minutes; // and display minutes with 0 appended
    }
    if(minutes > 9) { // until minutes reach 10
        minutesEl.innerHTML = minutes; // and then we display full minutes, without 0
    }
}

And there you have it, a fully functioning stopwatch.

However, a code can be further improved and prevent a bug that occurs…

Fixing a Bug

The bug is following: if you continue to press startBtn, before stoping or restarting a stopwatch, it will continue to add a calling of the countTime function, causing the counting of time to speed up. In addition, it will not be possible to stop or restart the stopwatch.

You can see the problem bellow:

How to fix this problem?

To fix this problem, we need to check if our start button was already clicked or not. If yes, every new clicked will do nothing. If not, start executing the function.

First, we need to create a variable which will store the information about our button:

let startBtnClicked = false; // here we will store our startBtn status
// when we load a stopwatch, the button is not clicked, so the variable value will be false

Now, when we actually click startBtn, we want to check for the button status. If it is false, execute. If true, do nothing.

startBtn.addEventListener('click', ()=>{ // when we click on startBtn
    if(startBtnClicked) { // first we check if startBtnClicked is true
        return false; // if true, our start button is clicked, so the code will do nothing and exit
    }
    else { // however, in other case, startBtnClicked is false, button is not clicked
        time = setInterval(countTime,10); // execute the function
        startBtnClicked = true; // and change its status to true, so no further clicks are possible
    }
})

This fixed our startBtn problem, and once we click on the Start, every next click will do nothing, as our startBtnClicked variable will have the value true, so no further actions are possible.

Having the rules set in this way, no click on the Start button is possible after we have clicked on it once. So stopping or resetting the stopwatch changes nothing, and we are not able to start the stopwatch again.

To make startBtn work again if stopwatch is stopped or restarted, we just need to change startBtnClicked to its default value (false) when we click on either of them:

stopBtn.addEventListener('click', ()=>{
    clearInterval(time);
    startBtnClicked = false; // we added this line, to change start button status back to false and make it usable again after clicking on Stop
})

restartBtn.addEventListener('click', ()=>{
    clearInterval(time);
    hundreds = 0;
    seconds = 0;
    minutes = 0;
    hundredsEl.innerHTML = "00";
    secondsEl.innerHTML = "00";
    minutesEl.innerHTML = "00";
    startBtnClicked = false; // and also here, for Restart button
})

And there we have it. Fully functional JavaScript Stopwatch.

The JavaScript code all together:

// timer HTML elements
const minutesEl = document.getElementById('minutes');
const secondsEl = document.getElementById('seconds');
const hundredsEl = document.getElementById('hundreds');

// buttons
const startBtn = document.getElementById('start');
const stopBtn = document.getElementById('stop');
const restartBtn = document.getElementById('restart');

// timer values
let minutes = 0;
let seconds = 0;
let hundreds = 0;

let time; // variable to store time duration value

let startBtnClicked = false; // start button status

startBtn.addEventListener('click', ()=>{
    if(startBtnClicked) {
        return false;
    }
    else {
        time = setInterval(countTime,10);
        startBtnClicked = true;
    }
})

stopBtn.addEventListener('click', ()=>{
    clearInterval(time);
    startBtnClicked = false;
})

restartBtn.addEventListener('click', ()=>{
    clearInterval(time);
    hundreds = 0;
    seconds = 0;
    minutes = 0;
    hundredsEl.innerHTML = "00";
    secondsEl.innerHTML = "00";
    minutesEl.innerHTML = "00";
    startBtnClicked = false;
})

function countTime() {
    hundreds++; // start adding hundreds of a second with every function call

    if(hundreds < 10) { // while hundreds count is under 10
        hundredsEl.innerHTML = "0" + hundreds; // we append 0 to hundreds number
    }
    if(hundreds >= 10) { // when hundreds are equal or greater than 10
        hundredsEl.innerHTML = hundreds; // we display hundreds
    }
    if(hundreds > 99) { // when hundreds count reaches 100
        seconds++; // we add 1 second
        hundreds = 0; // restart hundreds
        secondsEl.innerHTML = "0" + seconds; // and display seconds, with 0 appended
    }
    if(seconds > 9) { // when seconds count reach 10
        secondsEl.innerHTML = seconds; // we display seconds, no need for 0 in front
    }
    if(seconds > 59) { // when seconds reach 60
        minutes++; // we add minute
        seconds = 0; // restart seconds
        hundreds = 0; // restart hundreds
        minutesEl.innerHTML = "0" + minutes; // and display minutes with 0 appended
    }
    if(minutes > 9) { // until minutes reach 10
        minutesEl.innerHTML = minutes; // and then we display full minutes, without 0
    }
}

Conclusion

That is how you can create your own JavaScript Stopwatch.

There are other ways to achieve the same result, maybe even more effective ways. Feel free to play around with the code and improve it.

Please leave a comment if you like. Any feedback is helpful, as we all are learning this together.

Thank you for reading.

%d bloggers like this: