Create a Pomodoro Timer App using HTML, CSS, and JavaScript

Noori Ameer
5 min readApr 28, 2024

--

Photo by Towfiqu barbhuiya on Unsplash

We will build the Pomodoro timer app using HTML, CSS, and JavaScript in this tutorial. Let’s break down the HTML structure.

index.html

First, Create a container for Pomodoro timer components. Within the container, we have buttons for Pomodoro, short break, and long break timer modes. Create one section to display the Pomodoro count. We will address its functionality later in this tutorial. Create a progress bar and countdown timer section. After that, create a section for buttons for start, pause, and reset functions.

</head>
<body>
<div class="container">
<div class="timer-container">
<button id="pomodorobtn" class="active">Pomodoro</button>
<button id="shortbrkbtn">Shortbreak</button>
<button id="longbrkbtn">Long break</button>
</div>
<div class="pomdoro-count"></div>
<div class="progressbar">
<div class="progrsbar-inner">
<h2 class="progressbar-number">25:00</h2>
</div>
</div>
<div class="function-buttons">
<button id="startbtn">Start</button>
<button id="pausebtn">Pause</button>
<button id="resetbtn">Reset</button>
</div>
</div>
</body>
</html>

index.css

Here is the CSS for the container and timer-container classes.

body {
margin: 0;
padding: 0;
box-sizing: border-box;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: "Roboto", sans-serif;
}
.container {
width: 400px;
height: 400px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #00003D;
padding: 50px 20px;
border-radius: 15px;
}

.timer-container {
margin-bottom: 50px;
display: flex;
align-items: center;
justify-content: space-between;
width: 80%;
}

Apply CSS for timer mode buttons Pomodoro, short break, and long break. Add a background-color property for the active class this will apply to the currently active button Pomodoro mode.

.timer-container button {
padding: 10px;
border: none;
border-radius: 5px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 1);
color: #ffffff;
font-weight: bold;
background-color: #f3486d;
cursor: pointer;
}
.timer-container button: hover {
transform: scale(1.2);
}
.timer-container .active {
background-color: #db2a34;
}

The long break button will be displayed after completing the 4 Pomodoro Cycle so we will add the display: none property to the long break button. The Pomodoro count section will show after starting the timer so we will make it also display: none

#longbrkbtn {
display: none;
}
.pomdoro-count {
margin-bottom: 20px;
display: none;
font-weight: 800;
}
.function-buttons {
display: flex;
align-items: center;
justify-content: space-between;
width: 80%;
}
.function-buttons button: hover {
transform: scale(1.2);
}

Write CSS for the start, pause, and reset buttons and progress bar. Add animation and transition to the progress bar.

#startbtn,
#pausebtn,
#resetbtn {
padding: 10px 20px;
border: none;
border-radius: 5px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 1);
color: #ffffff;
font-weight: bold;
background-color: #f3486d;
cursor: pointer;
}
#startbtn {
background-color: #008000;
}
#pausebtn {
background-color: #db2a34;
}
#resetbtn {
background-color: #ffa600;
}
.progressbar {
height: 180px;
width: 180px;
background: conic-gradient(crimson 0deg, rgb(243, 72, 109)
0deg);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
animation: pulse 3s infinite;
transition: all ease;
margin-bottom: 50px;
}
.progrsbar-inner {
height: 90%;
width: 90%;
background:#03033f;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.progressbar-number {
color: #ffffff;
font-weight: 900;
font-size: 2rem;
}
@keyframes pulse {
0% {
transform: scale(0.97);
}
50% {
transform: scale(1);
}
100% {
transform: scale(0.97);
}
}

index.js

Add index.js file to the HTML file.

<script src="index.js"></script>
</body>
</html>

Create variables for all buttons, the progress bar, and the Pomodoro count section.

const startBtn = document.querySelector("#startbtn");
const stopBtn = document.querySelector("#pausebtn");
const resetBtn = document.querySelector("#resetbtn");
const progressbar = document.querySelector(".progressbar");
const progressbarNumber = document.querySelector(".progressbar .progressbar-number");
const pomodoroBtn = document.getElementById("pomodorobtn");
const shortbrkBtn = document.getElementById("shortbrkbtn");
const longbrkBtn = document.getElementById("longbrkbtn");
const pomCount = document.querySelector(".pomdoro-count");

Initialize Pomodoro count as 0. Set Pomodoro count for long break availability, Pomodoro, short break, and long break time, and make the initial Pomodoro timer type POMODORO. The initial timer value will be the value of the Pomodoro timer.

let pomdoroCount = 0;
const pomodorountilLongbrk = 4;
const pomodorotimer = 1500; /* 25 minutes*/
const shortbreaktimer = 300; /* 5 minutes*/
const longbreaktimer = 900; /* 20 minutes*/
let timerValue = pomodorotimer;
const multipliervalue = 360 / timerValue;
let progressInterval;
let pomodoroType = "POMODORO";

Add event listener to all the buttons. Now, we will jump into the logic part of the code.

startBtn.addEventListener("click", () => {
startTimer();
});
stopBtn.addEventListener("click", () => {
pauseTimer();
});
pomodoroBtn.addEventListener("click", () => {
setTimeType("POMODORO");
});
shortbrkBtn.addEventListener("click", () => {
setTimeType("SHORTBREAK");
});
longbrkBtn.addEventListener("click", () => {
setTimeType("LONGBREAK");
});
resetBtn.addEventListener("click", () => {
resetTimer();
});

Write a start timer function. create setInterval function, and store that function into progressInterval variable. The value of the countdown timer and the status of the progress bar will be specified using the setProgressInfo() function. Clear the interval and increase the Pomodoro count if the timer value is 0.

We will modify the Pomodoro count section’s style attribute to display: block to display the Pomodoro count value in the user interface. Four Pomodoro counts later, a long break button appears.

function startTimer() {
progressInterval = setInterval(() => {
timerValue--;
console.log(timerValue);
setProgressInfo();
if (timerValue === 0) {
clearInterval(progressInterval);
pomdoroCount++;
pomCount.style.display = "block";
pomCount.style.color = "white";
pomCount.style.fontSize = "30px";
pomCount.textContent = `Pomodoro Count ${pomdoroCount}`;
if (pomdoroCount % pomodorountilLongbrk === 0) {
longbrkBtn.style.display = "flex";
}
setTimeType(pomodoroType);
}
}, 1000);

function setProgressInfo() {
progressbarNumber.textContent = `${FormatNumbertoString(timerValue)}`;
progressbar.style.background = `conic-gradient(rgb(243, 72, 109) ${
timerValue * multipliervalue
}deg,crimson 0deg)`;
}

The countdown timer time value will be converted from number to string in the FormatNumbertoString function.

function NumbertoString(number) {
const minutes = Math.trunc(number / 60).toString()
.padStart(2, "0");
const seconds = Math.trunc(number % 60).toString()
.padStart(2, "0");
return `${minutes}:${seconds}`;
}

clear interval in the pause timer function.

function pauseTimer() {
clearInterval(progressInterval);
}

We will set the timer type using this function.

function setTimeType(type) {
pomodoroType = type;
if (type === "POMODORO") {
pomodoroBtn.classList.add("active");
shortbrkBtn.classList.remove("active");
longbrkBtn.classList.remove("active");
} else if (type === "SHORTBREAK") {
pomodoroBtn.classList.remove("active");
shortbrkBtn.classList.add("active");
longbrkBtn.classList.remove("active");
} else {
pomodoroBtn.classList.remove("active");
shortbrkBtn.classList.remove("active");
longbrkBtn.classList.add("active");
}
resetTimer();
}

In resetTimer function, clear interval and change the timer value according to the timer mode type.

function resetTimer() {
clearInterval(progressInterval);
timerValue =
pomodoroType === "POMODORO"
? pomodorotimer
: pomodoroType === "SHORTBREAK"
? shortbreaktimer
: longbreaktimer;
multipliervalue = 360 / timerValue;
setProgressInfo();
}

Congrats 🎉! you have successfully built the Pomodoro timer. Now, our app will look like this.

I hope you found this tutorial helpful! If you have any concerns or questions, please feel free to leave a comment. Your feedback is always appreciated!

--

--