December Go Design Something Project: Building a Pomodoro Timer App

Pomodoro timer concept

As a developer, you know how important it is to stay focused and manage your time effectively. The Pomodoro Technique is a popular time management method that can help boost productivity by splitting work into focused 25-minute sessions separated by short breaks. In this article, I‘ll walk you through how I built a web-based Pomodoro timer app and share tips and best practices along the way.

Planning the App

Before diving into the code, I sketched out a basic design for the app‘s interface. The main screen would display the current timer and buttons to start, pause, and reset it. Additional controls could allow the user to adjust the length of the work sessions and breaks.

Under the hood, the app would need to:

  • Keep track of the current session (work or break) and time remaining
  • Start a new timer when the user clicks the "Start" button
  • Pause and resume the timer when the user clicks "Pause"
  • Reset the timer when "Reset" is clicked
  • Sound an alarm or notification when the session ends
  • Automatically start the next session after a short break
  • Allow the user to specify custom session and break durations

With these requirements in mind, I was ready to start developing the app.

Setting Up the Project

To begin, I created a new directory for the project with the following structure:

pomodoro-timer/
  index.html
  styles.css
  script.js

In the index.html file, I added the basic structure of the app‘s interface:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Pomodoro Timer</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="timer">
    <div class="time">25:00</div>
    <button class="start">Start</button>
    <button class="pause">Pause</button>
    <button class="reset">Reset</button>
  </div>

<div class="settings"> <label for="work-time">Work Time:</label> <input type="number" id="work-time" value="25" min="1"> <label for="break-time">Break Time:</label> <input type="number" id="break-time" value="5" min="1"> </div>

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

In styles.css, I added some basic CSS to style the timer and controls:

.timer {
  text-align: center;
  font-size: 6rem; 
}

button { font-size: 1rem; padding: 1rem 2rem; margin: 0 1rem; }

.settings { margin-top: 2rem; text-align: center; }

Implementing the Timer

Now came the fun part – making the timer actually work! In script.js, I started by defining variables to store the work and break durations and get references to the key elements:

let workTime = 25;
let breakTime = 5;

const timer = document.querySelector(‘.time‘); const startBtn = document.querySelector(‘.start‘); const pauseBtn = document.querySelector(‘.pause‘); const resetBtn = document.querySelector(‘.reset‘);

To implement the core timer functionality, I defined a startTimer function that would begin a new countdown based on the current session:

let countdown;

function startTimer() { let seconds = workTime * 60; countdown = setInterval(() => { seconds--; displayTime(seconds);

if (seconds <= 0) {
  clearInterval(countdown);
  alarm();

  if (currentSession === ‘work‘) {
    currentSession = ‘break‘;
    seconds = breakTime * 60;
  } else {
    currentSession = ‘work‘;
    seconds = workTime * 60;
  }
  startTimer();
}

}, 1000);
}

This function uses setInterval to decrement the remaining seconds every 1000ms (1 second). It displays the current time using a displayTime helper function and plays an alarm sound when the session ends using an alarm function. It then automatically starts the next session.

To allow pausing and resuming the timer, I added the following code:

let isRunning = false;

function pauseTimer() { clearInterval(countdown); isRunning = false; }

function resumeTimer() {
if (!isRunning) { isRunning = true; startTimer(); } }

The pauseTimer function stops the current countdown, while resumeTimer starts it again if the timer isn‘t already running.

Resetting the timer was a simple matter of stopping the current countdown and resetting the time display:

function resetTimer() {
  clearInterval(countdown);
  isRunning = false;
  currentSession = ‘work‘;
  displayTime(workTime * 60);
}

Finally, I added event listeners to the control buttons to trigger the appropriate actions:

startBtn.addEventListener(‘click‘, startTimer);
pauseBtn.addEventListener(‘click‘, pauseTimer);
resetBtn.addEventListener(‘click‘, resetTimer);

With that, the core functionality of the Pomodoro timer was complete!

Extending and Customizing the App

With the basic timer working, I moved on to implementing some additional features to make the app more useful and customizable.

First, I added the ability for users to set custom session and break lengths using the number input fields in the HTML:

const workInput = document.getElementById(‘work-time‘);
const breakInput = document.getElementById(‘break-time‘);

workInput.addEventListener(‘change‘, () => { workTime = parseInt(workInput.value); });

breakInput.addEventListener(‘change‘, () => {
breakTime = parseInt(breakInput.value); });

Whenever the user changes the work or break time, these event listeners update the corresponding variables.

Another useful feature was the ability to track the number of completed Pomodoros over time. To implement this, I added a pomodoroCount variable and incremented it whenever a work session completed:

let pomodoroCount = 0;

function startTimer() { // ... if (currentSession === ‘work‘) { pomodoroCount++; updateDisplay(); } // ... }

function updateDisplay() { const count = document.querySelector(‘.pomodoro-count‘); count.textContent = Pomodoros: ${pomodoroCount};
}

I then updated the HTML to include an element to display the Pomodoro count:

<div class="pomodoro-count">Pomodoros: 0</div>  

To further enhance the app, I also experimented with adding some visual indicators and animations. For example, I used CSS transitions to smoothly update the timer display:

.time {
  transition: all 0.5s ease-in-out;
}

I also added a circular progress bar around the timer using an SVG:

<div class="progress-ring">
  <svg>
    <circle class="progress-ring__circle" />
  </svg>
</div>

To animate the progress bar, I used JavaScript to calculate the stroke dashoffset based on the remaining time:

function updateProgressBar(seconds) {
  const circle = document.querySelector(‘.progress-ring__circle‘);
  const radius = circle.r.baseVal.value;
  const circumference = radius * 2 * Math.PI;

const elapsed = (workTime 60 - seconds) / (workTime 60); const offset = circumference * (1 - elapsed);

circle.style.strokeDasharray = ${circumference} ${circumference}; circle.style.strokeDashoffset = offset; }

These extra touches helped make the Pomodoro timer app feel more polished and engaging to use.

Lessons Learned

Building this Pomodoro timer was a great learning experience that reinforced my understanding of several key web development concepts:

  • Manipulating the DOM with JavaScript to dynamically update the app‘s interface
  • Using intervals and timeouts to implement timed functionality
  • Handling user input with event listeners
  • Creating reusable helper functions to keep code modular
  • Styling elements with CSS to create visual polish

It also gave me good practice with breaking down a project into smaller, manageable tasks and iteratively developing and testing the app. Getting the basic timer functionality working first before moving on to more advanced features helped keep the project on track.

Going forward, there are several ways this Pomodoro timer could be extended even further, such as:

  • Persisting Pomodoro history and stats across sessions using local storage
  • Providing more configuration options (e.g. different alarm sounds, color themes)
  • Integrating with a backend API for more robust data storage and syncing across devices
  • Adding social features to compete or collaborate with friends

Conclusion

Creating a Pomodoro timer web app is a great project for beginner to intermediate developers looking to sharpen their front-end development skills. It provides an opportunity to work with core web technologies like HTML, CSS, and JavaScript while also diving into more complex programming concepts.

By planning out the app‘s functionality, iteratively implementing features, and adding some visual flair, you can create a practical and polished productivity tool you‘d be happy to use yourself. Hopefully this walkthrough has given you a good starting point and some inspiration for building your own Pomodoro timer. Happy coding!

Similar Posts