Browser Pomodoro Timer
Build a Pomodoro timer web page with plain HTML, CSS and JavaScript, no frameworks. It runs a 25-minute work session, then a 5-minute break (and a longer break after every 4 sessions), with start, pause and reset buttons. When a session ends it plays a sound made with the Web Audio API and switches automatically, and it keeps a history of completed sessions in localStorage with today's total. The timer stays accurate even in a background tab, because it's based on the real clock rather than counting ticks. It's a great first JavaScript project: you'll learn working with the page (the DOM), events, timers, the Web Audio API, and saving data in the browser.
- Estimate
- ~6.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Vanilla JS · localStorage · Web Audio API
Project roadmap
- 01
Build the page
~1hCreate index.html, style.css and app.js. Lay out a large mm:ss display, the current phase (Work, Short break or Long break), a session counter, and Start, Pause and Reset buttons. Make it look good on phones and give each phase its own color. Done when: the page shows the layout, and the buttons respond to clicks (logging to the console for now).
- 02
Count down accurately
~1.5hWhen Start is pressed, save the end time (Date.now() plus the duration), and every 250 ms compute the remaining time from the end time and update the display and the page title. Pause saves the remaining time; resume sets a new end time. Using the clock instead of counting ticks keeps it accurate even when the browser slows timers in background tabs. Done when: the timer counts down correctly, pauses and resumes.
- 03
Switch between work and breaks
~1hWhen the time reaches zero, record the session if it was work, then move to the next phase: a short break, or a long break after every 4th work session. Add a setting for whether the next phase starts automatically. Add a Skip button. Done when: the timer cycles through work and breaks in the right order.
- 04
Play a sound
~1hCreate an AudioContext on the first click (browsers only allow sound after the user interacts), and play a short chime when a phase ends using an OscillatorNode and a GainNode that fades out. Add a mute toggle. Done when: a chime plays at the end of each phase, and muting stops it.
- 05
Save the history
~1hSave completed work sessions (with their end time) and the settings in localStorage as JSON, and show today's number of sessions and total focus time. Restore a running timer after reloading from its saved end time. Handle missing or broken saved data by starting fresh. Done when: the history and a running timer survive reloading the page.
- 06
Test it
~1hPut the timing logic (remaining time, next phase and today's totals) in functions that don't touch the page, and test them with a few assertions in a test page or with Vitest. Test by hand: a background tab, pausing, and reloading mid-session. Done when: the logic tests pass, and the manual checks work.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack