Building a Customizable Pomodoro Timer with JavaScript
January 06, 20255 min read

Building a Customizable Pomodoro Timer with JavaScript

Web developmentJavaScriptCSS3Programming
share this article on
In this article, we will create a Pomodoro Timer using HTML, CSS, and JavaScript. The timer will allow users to set work and break intervals, automatically switch between sessions, and include features like animations and sound alerts. This project is beginner-friendly and a great way to practice JavaScript concepts such as DOM manipulation and timers.

Features of the Pomodoro Timer:

  1. Customizable Work Time and Break Time durations.
  2. Automatic transition between work and break sessions.
  3. Visual color feedback when the timer ends.
  4. Sound notification for session transitions.
  5. Zoom-in animation for the timer display.

Step 1: Setting Up the HTML Structure

The HTML structure includes input fields for setting work and break durations, a display for the timer, and controls for starting, pausing, and resetting the timer.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Pomodoro Timer</title>
  <link rel="stylesheet" href="styles.css">
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">

</head>
<body>
  <div class="timer-container">
    <h1 id="timer">25:00</h1>
    <div class="settings">
      <div class="time-input">
        <label for="work-time">Work (mins):</label>
        <input type="number" id="work-time" value="2" min="1">
      </div><div class="time-input">
        <label for="break-time">Break (mins):</label>
        <input type="number" id="break-time" value="1" min="1">
      </div>
    </div>
    <div class="controls">
      <button id="start-btn">
        <i class="fas fa-play"></i> Start
      </button>
      <button id="pause-btn" disabled>
        <i class="fas fa-pause"></i> Pause
      </button>
      <button id="reset-btn" disabled>
        <i class="fas fa-redo"></i> Reset
      </button>
    </div>
    <audio id="alarm-sound" src="alarm.wav"></audio>
  </div>
  <script src="script.js"></script>
</body>
</html>

Step 2: Styling with CSS

The CSS styles the timer, input fields, and buttons, adding visual appeal and an animation for the timer display.

body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
  font-family: Arial, sans-serif;
  background-color: #f7f7f7;
}

.timer-container {
  text-align: center;
  background-color: #ffffff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  width: 300px;
}

#timer {
  font-size: 3em;
  margin: 20px 0;
  color: #4caf50;
  transition: color 0.3s ease;
}

.zoom {
  animation: zoom-in 0.3s ease;
}

@keyframes zoom-in {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
  }
}

.settings {
  display: flex;
  justify-content: space-around;
  margin-bottom: 20px;
}

.time-input {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

.settings label {
  font-size: 0.9em;
}

.settings input {
  width: 60px;
  padding: 5px;
  text-align: center;
  font-size: 1em;
}

.controls {
  display: flex;
  justify-content: space-between;
}

.controls button {
  flex: 1;
  margin: 5px;
  padding: 10px 15px;
  font-size: 1em;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  color: #fff;
}

#start-btn {
  background-color: #4caf50;
  }

#pause-btn {
  background-color: #ff9800;
  }

#reset-btn {
  background-color: #f44336;
  }

.controls button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

Step 3: Adding Functionality with JavaScript

The JavaScript adds the core functionality to the timer, enabling users to start, pause, and reset it, as well as switch between work and break sessions automatically.

let timerDisplay = document.getElementById("timer");
let startBtn = document.getElementById("start-btn");
let pauseBtn = document.getElementById("pause-btn");
let resetBtn = document.getElementById("reset-btn");

let workInput = document.getElementById("work-time");
let breakInput = document.getElementById("break-time");

let alarmSound = document.getElementById("alarm-sound");

let isRunning = false;
let isWorkTime = true; // Keeps track of whether it's work or break time
let timerInterval;
let timeRemaining;

// Update the timer display when inputs change
workInput.addEventListener("input", () => {
  if (!isRunning) {
    isWorkTime = true; // Ensure it's set to work time
    updateDisplay(workInput.value * 60);
  }
});

breakInput.addEventListener("input", () => {
  if (!isRunning && !isWorkTime) {
    updateDisplay(breakInput.value * 60);
  }
});

// Function to start the timer
function startTimer() {
  if (!isRunning) {
    isRunning = true;

    // If no time is set, initialize based on the current session
    if (!timeRemaining) {
      timeRemaining = isWorkTime ? workInput.value * 60 : breakInput.value * 60;
    }

    timerInterval = setInterval(() => {
      if (timeRemaining > 0) {
        timeRemaining--;
        updateDisplay(timeRemaining);
        addZoomEffect(); // Add animation effect on each update
      } else {
        clearInterval(timerInterval);
        alarmSound.play();
        timerDisplay.style.color = "#e74c3c"; // Change color to red
        setTimeout(() => switchTimer(), 1000); // Wait 1 second before switching
      }
    }, 100);

    toggleButtons();
  }
}

// Function to pause the timer
function pauseTimer() {
  isRunning = false;
  clearInterval(timerInterval);
  toggleButtons();
}

// Function to reset the timer
function resetTimer() {
  isRunning = false;
  clearInterval(timerInterval);
  timeRemaining = null;
  isWorkTime = true; // Reset to work session
  updateDisplay(workInput.value * 60); // Reset display to work time
  timerDisplay.style.color = "#4caf50"; // Reset color to green
  toggleButtons();
}

// Function to update the timer display
function updateDisplay(seconds) {
  let minutes = Math.floor(seconds / 60);
  let secs = seconds % 60;
  timerDisplay.textContent = `${minutes.toString().padStart(2, "0")}:${secs
    .toString()
    .padStart(2, "0")}`;
}

// Add zoom-in animation effect
function addZoomEffect() {
  timerDisplay.classList.add("zoom");
  setTimeout(() => timerDisplay.classList.remove("zoom"), 300);
}

// Function to toggle buttons
function toggleButtons() {
  startBtn.disabled = isRunning;
  pauseBtn.disabled = !isRunning;
  resetBtn.disabled = !isRunning && !timeRemaining;
}

// Function to switch between work and break time
function switchTimer() {
  isWorkTime = !isWorkTime; // Toggle between work and break
  timeRemaining = isWorkTime ? workInput.value * 60 : breakInput.value * 60; // Set the next duration
  timerDisplay.style.color = "#4caf50"; // Reset color to green for the new session
  updateDisplay(timeRemaining); // Update the display for the next session
  isRunning = false;
  // Automatically start the next session:
  startTimer(); // Comment this out if you want manual start for the next session
}

// Initialize the display with the default work time
updateDisplay(workInput.value * 60);

// Event listeners
startBtn.addEventListener("click", startTimer);
pauseBtn.addEventListener("click", pauseTimer);
resetBtn.addEventListener("click", resetTimer);

Key Functionalities Explained:

  1. Timer Initialization:
  1. Session Switching:
  1. Animation and Feedback:
  1. Control Buttons:

Conclusion

This customizable Pomodoro Timer is a practical tool to boost productivity. With user-friendly customization options, visual feedback, and sound notifications, it can be further enhanced with features like session tracking or dark mode.


Back to Articles