In this project, we’ll be recreating a functional chronograph analog watch using just Vanilla JavaScript and HTML, with a bit of CSS for styling.
It’s been a long time since I haven’t worked with any pure HTML and Vanilla JS. I decided to choose the chronograph watch as the project since I love my watch so much! This project enables us to explore fundamental web development concepts, such as DOM manipulation, event handling, and animations.

The project
-
Create a mechanical watch dial.
-
Has 12-hour marks.
-
The main second hand is the chronograph second, while the hour and minute hands show real-time.
-
The sub-dial is on at the 9-hour position for the real second-hand.
-
The sub-dial is at the 3-hour position for the elapsed minute hand.
-
Movement of 4hz — the second hand moves four times in one second to emulate the weeping hand.
-
Start, stop and reset functionalities.
Multiple trips to the mountain
To deliver the project, we can break it down into multiple phases
-
Draw the basic analog dial. ← This pt1 is about
-
Add a sub-second dial. ← the next part is here https://medium.com/@whoz_/lets-build-an-analog-chronograph-watch-with-vanillajs-html-pt-1-4db16d182983
-
Add chronograph function.
The Basic Analog Dial
First, we need to create 3 files: index.html , app.js and style.css
The main HTML file
It’s just a simple layout with a dial and the 3 hands. For the 12-hour marks, we can put the 12 div here, but I would prefer to add it in the JS file to follow the DRY.
1 |
|
The CSS file
From the HTML file, we can see that we have the hand class as shared so we don’t have to duplicate props. The key here is we want to have the transform-origin: bottom , which acts like an anchor when we transform the hand position.
1 | *, |
We start to get the shape of the watch!

The JS file
Since we have the basic UI, let’s make the watch work.
Now, we need to map the real-time to the HTML elements.
1 | const hourHand = document.querySelector('.hour-hand'); |
Starting from the heart, we need it to run 4 beats per second, aka 28880 bph, which is the standard in the mechanical watch world. The more high-end watch engine will have more beats for a second so the second-hand can move as smoothly as possible.
The takeaway here is we need to transform the hand rotate(${someDegree}deg) and combine with the anchor bottom from above we can have the basic hand movement.
1 | let realTimeInterval; |
And voila, we got the watch working!

Now let’s add the 12 mark by JS instead of the 12 repeated div. We can write a simple function to append divinto the dial.
1 | const dial = document.querySelector('.dial'); |
And add the CSS
1 | .hour-mark { |

Wrap up part 1
So far, we have implemented the basic analog watch with pure JS, HTML and CSS.
In the next part, we’re going to implement the chronograph function and make it look like my pilot watch.
Stay tuned for more!