Coding a Pomodoro Timer in HTML/JS/CSS

David Jordan
7 min readMay 19, 2020

I recently came across the Pomodoro Timer technique and I installed a VS Code extension to give it a try during my coding sessions at work. I thought that it was such a good idea to break up focus into 25 minute sessions with 5 minutes of rest to assess how much I achieved and what I should do in my next 25 minute session. I have not been 100% strict on taking the 5 minute rest in some sessions because I have found myself in a flow state that meant I was achieving the highest quality work (by my own standards) during a longer session.

So this weekend, I thought it would be interesting to re-create the Pomodoro Timer as a mobile web app using the skills and knowledge that I have about web application development. My goals for this exercise were the following:

  • Simplicity; The UI must be very basic and minimal. The design does not need to be fancy. No animations or flashing colours.
  • Native HTML, JavaScript, CSS. No third party component framework or CSS pre/post processors.
  • Add to home screen capability so I can use this quickly and easily whenever I want.
  • And lastly, to create a working pomodoro timer.

Step 1 — Think about and plan the user actions.

Before I started coding I wanted to think about the end result and how the user would use the app and from this I could work backwards to define all the data, actions and constraints I would need to include to make this app work.

From this exercise I determined the following things:

  • The timer name must be displayed. Either “Work” or “Rest” depending on the current timer.
  • The timer countdown must be displayed. Either “25:00” or “5:00” depending on the current timer.
  • A start/stop button must be displayed. “Start” when no timer is currently running and “Stop” when there is a timer running.
  • A user can start the 25 minute timer. At the end of the 25 minute timer a 5 minute timer will automatically start.
  • A user can stop any timer only when a timer is currently running.
  • When the final timer finishes the user interface will reset back to the initial state with the timer name set to “Finished”.

Step 2 — Iterative design.

Writing the HTML

At this point I got stuck into coding starting off with the HTML side of things. I knew what data I wanted to display so I could easily write the HTML for this with an idea in mind of the simplistic design of the app. The result of that was the following HTML inside the <body> tags.

I gave ‘id’ attributes to every element that I felt I might need to change in the JavaScript. I kept the timer duration and name together in one <div> so I could more easily add spacing between those elements and the button. I did not use any ‘class’ attributes even though it is best practice because I knew how simple the CSS and JavaScript was going to be. It was not necessary to add further complexity.

Writing the CSS

With the design, I knew I wanted it to be a non-scrollable full screen mobile web page. I have never created something like this before so I only had some vague ideas on how I could achieve this with CSS.

The first part of the design actually involves another HTML change. I added the following line inside the <head> tags.

<meta name="viewport" content="width=device-width, initial-scale=1">

I may tweak this in future as I research more into full page web apps because I found that pinch-to-zoom is still possible.

Now I can get into the CSS for this app. The elements in the design will be stacked in a column and there will be adequate spacing around the edges of the viewport and in between related and unrelated components.

At this stage I also wanted to use some better colours than just black and white (the usual boring colours used in prototypes). I had one word and colour pop into my head and that was ‘gunmetal’. I googled it and chose the first result that gave me the hex colour code #2A3439. This is a dark colour so I wanted to use it as the background colour with white text for maximum contrast.

The CSS that I eventually came up with for the page layout is:

I am not trying to be cross-browser compatible with this prototype, my intention is to use Google Chrome to add the web page to my Android phone’s home screen. So I am using ‘vh’ units and CSS Grid to achieve the design I want with minimal effort and relative ease.

To finish off the CSS changes I needed to update the font sizes, spacing and button design of the remaining elements inside the page layout.

Through some experimentation and tweaking I ended up with the following CSS rules:

I used ‘vmin’ on font sizes to achieve big text that would shrink if the viewport width was smaller and grow to the number I set on larger screens. This works pretty well at making sure the design looks good on any mobile or tablet device.

That is all I needed to achieve the following design:

A preview of the pomodoro timer design with timer name, timer duration, and start button.
Basic pomodoro timer design.

Step 3 — Interaction and state changes

From my initial specification I quickly realised there were only two states that this app could be in:

  • Stopped — Nothing is happening on the page.
  • Running — A timer is in progress and the page is updating.

When a user first visits the app it will be in the ‘Stopped’ state. When a user presses the start button it will move to the ‘Running’ state. If a user presses the stop button it will move back to the ‘Stopped’ state.

My initial approach to writing the JavaScript was to use functional programming however I love object oriented programming and I have ideas to re-use the JavaScript I write now in other projects.

There are three classes that I ended up writing for this app. They are:

  • Timer; Represents a timer and is immutable.
  • TimerQueue; Represents a queue of Timer objects.
  • PomodoroTimerComponent; Keeps track of the timer queue and UI changes.

The Timer and TimerQueue classes are simple and re-usable. The method names I used for the TimerQueue class were inspired by PHP’s Ds\Queue class.

The Timer class looks like:

The TimerQueue class looks like:

The reason the TimerQueue is not a generic Queue class is so that the docblock comments I added would aid me in writing the rest of the JavaScript using VS Code’s intellisense and code-completion capabilities.

Now for the main component and timer logic; I have called it PomodoroTimerComponent without any experience with web component frameworks like React or Angular, however I have briefly read their documentation on how components are written and structured. This knowledge allowed me to write a component class in JavaScript that is similar to those frameworks without all the bells and whistles that those frameworks provide. This works quite well for this simple app.

As you can probably tell by now I am using ES6 class syntax to define these classes. For the PomodoroTimercomponent class I have the following methods:

  • constructor(options={}) — Constructor with one supported option, the defaultTimerQueue. This option was used during testing to use much lower durations on the timers to make sure it would work as expected when the timers ended.
  • initEventHandlers() — Creates DOM event handlers.
  • render() — Updates the DOM based on state changes that occur in triggered events.
  • formatDuration(duration_in_seconds) — Formats number of seconds into the “25:00” format.
  • createTimerQueue() — Creates the pomodoro timer queue with a 25 minute and 5 minute timer in the queue.
  • getNextTimerFromQueue() — When a timer ends this function will ‘pop’ the next timer in the queue off and return it.
  • event_startTimer() — When a timer is started by pressing the ‘Start’ button this function will be triggered. Puts it into the Running state.
  • event_stopTimer() — When there are no more timers in the queue or the ‘Stop’ button is pressed this function will be triggered. Puts it into the Stopped state.

After some iterations of method implementations I eventually ended up with the following JavaScript:

So from all this I have version 1 of this mobile app working and added to my phone’s home screen.

You can view it here: http://itsdavidjordan.co.uk/pomodorotimer

Step 4 — ?

In every project there is always future work, feature creep, new ideas, regular updates.

My next steps with this is to try and improve it further by researching more into how I can make use of other JavaScript APIs to further enhance the functionality of the app.

Some interesting APIs and ideas are:

  • Canvas API — Graphics and animations showing timer duration to supplement the text. Something subtle like a cup filling up where the rest period would see the cup empty out again to symbolise having a break.
  • Fullscreen API — To remain distraction free as the “Work” timer is running a full screen web page would be ideal after pressing the “Start” button.
  • Vibration API — To physically tell you when a timer has finished.
  • Web Audio API — To play a short tone when the timer is up so you can audibly hear it.

That’s all I have for today though. I hope you found this interesting and if you have any ideas or suggestions please let me know.

--

--

David Jordan

Interested in web development, personal development, ju jitsu, gaming, fitness.