Create a Pomodoro Timer App using HTML, CSS, and JavaScript
Tags: javascript, beginners, codenewbie, frontend
Published: 2024-04-28 03:43:31


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


**<u>index.html</u>**

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.
```html
</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>
```
**<u>index.css</u>**

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

```css
 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.

```css
.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**

```css
#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. 

```css
#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);
        }
      }
```

**<u>index.js
</u>**

Add index.js file to the HTML file.

```html
  <script src="index.js"></script>
</body>
</html>
```
Create variables for all buttons, the progress bar, and the Pomodoro count section.
```javascript
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.

```javascript
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.

```javascript
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.
```javascript
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.

```javascript
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. 

```javascript
function pauseTimer() {
        clearInterval(progressInterval);
      }
```
We will set the timer type using this function.

```javascript
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.

```javascript
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.


![Pomodoro timer app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k3nz2vnf3af0pmj8jqo5.png)

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!