Clock with ReactJS & CSS

Dimterion
5 min readMay 10, 2024

--

Title: Clock with ReactJS & CSS.

Let’s make a simple clock with just ReactJS and CSS as a single component.

I needed some JavaScript practice recently and found another course with various exercises (insert a programming meme about starting new courses here). Then I decided to add an additional goal to it: converting the code to React. Here is a component for a clock from one of the exercises (with a few additions).

First, the HTML-part. I will use semantic <main> and <section> tags to store the clock and then three <span> tags for the clock hands (seconds, minutes and hours). No classes, just to make it simple.

function Clock() {
return (
<main>
<section>
<span></span>
<span></span>
<span></span>
</section>
</main>
)
}

export default Clock;

To make the clock work we need to write the following function:

function setTime() {
const now = new Date();

const seconds = now.getSeconds();
const secondsDegrees = (seconds / 60) * 360 + 90;
secondsRef.current.style.transform = `rotate(${secondsDegrees}deg)`;

const minutes = now.getMinutes();
const minutesDegrees = (minutes / 60) * 360 + (seconds / 60) * 6 + 90;
minutesRef.current.style.transform = `rotate(${minutesDegrees}deg)`;

const hours = now.getHours();
const hoursDegrees = (hours / 12) * 360 + (minutes / 60) * 30 + 90;
hoursRef.current.style.transform = `rotate(${hoursDegrees}deg)`;
}

The detailed description can be seen in the course linked above, here I am mostly talking about converting it to React, however, a brief description is:

  1. We add variable now to get the current date.
  2. We add three more variables to get seconds, minutes and hours (from the current date).
  3. We add three more variables to calculate the degrees to rotate each of the clock hands depending on the current time.
  4. We use current.style.transform with the degrees variables to point to the DOM elements to manipulate their style (so we can rotate each clock hand based on the time). To do this we will be using useRef hook from React instead of query selectors (see further explanation).

If we were using only JavaScript, we could just call this function, but, as we are dealing with React, we need to use useEffect hook, otherwise the clock will not be updating. Thus, our useEffect will be wrapping the function to make the clock ticking (all pun intended).

Additionally, we need to set a 1-second interval (1000ms) to update the clock every second, and we store it in another variable. Finally, we clear the interval in the return statement for useEffect.

Here is the updated version of the code above:

  useEffect(() => {
function setTime() {
const now = new Date();

const seconds = now.getSeconds();
const secondsDegrees = (seconds / 60) * 360 + 90;
secondsRef.current.style.transform = `rotate(${secondsDegrees}deg)`;

const minutes = now.getMinutes();
const minutesDegrees = (minutes / 60) * 360 + (seconds / 60) * 6 + 90;
minutesRef.current.style.transform = `rotate(${minutesDegrees}deg)`;

const hours = now.getHours();
const hoursDegrees = (hours / 12) * 360 + (minutes / 60) * 30 + 90;
hoursRef.current.style.transform = `rotate(${hoursDegrees}deg)`;
}

const intervalId = setInterval(setTime, 1000);

return () => clearInterval(intervalId);
}, []);

As was already mentioned, we also need to use useRef. In plain JavaScript we can use selectors to access the HTML elements (seconds/minutes/hours clock hands), so the function above is linked to them. It can also be used in React, however, it is better to use a dedicated hook for this (it avoids global scope and is better for performance in general). We add three variables at the top of our component for each clock hand and we set useRef to null. In setTime function these variables are used to change the clock hands rotate property.

Then we add ref attributes to our HTML code. Here is how it looks:

function Clock() {
const secondsRef = useRef(null);
const minutesRef = useRef(null);
const hoursRef = useRef(null);

return (
<main>
<section>
<span ref={secondsRef}></span>
<span ref={minutesRef}></span>
<span ref={hoursRef}></span>
</section>
</main>
)
}

export default Clock;

Now we have our component and all what is left is to add some CSS to it.

main {
width: 200px;
max-width: 90vw;
height: 200px;
max-height: 90vh;
padding: 10px;
border: 5px solid #e0e1dd;
border-radius: 50%;
margin: 5vh auto;
}

section {
width: 100%;
height: 100%;
transform: translateY(-3px);
}

section span:nth-child(1) {
width: 50%;
height: 2px;
background: #e63946;
}

section span:nth-child(2) {
left: 5%;
width: 45%;
height: 3px;
}

section span:nth-child(3) {
left: 10%;
width: 40%;
height: 4px;
}

span {
position: absolute;
top: 50%;
background: #e0e1dd;
transform: rotate(90deg);
transform-origin: 100%;
transition: all 0.05s;
transition-timing-function: cubic-bezier(0.1, 2.5, 0.55, 1);
}

<main> and <section> tags are more or less self-explanatory (and also can be checked in details in the mentioned course above). After that we add different width, height and position to the clock hands, so they can be distinguished by size (:nth-child is used for simplicity here, otherwise we could add classes to each element).

Finally, all clock hands (<span> tags) have transform property set to rotate(90deg). This is the main mechanic for the clock to work. Our function in useEffect updates this property every second, so the hands can move based on the time (transition property makes it look more like a real clock ticking).

Here is the final version of our Clock component:

import { useEffect, useRef } from "react";
import "./clock.css";

function Clock() {
const secondsRef = useRef(null);
const minutesRef = useRef(null);
const hoursRef = useRef(null);

useEffect(() => {
function setTime() {
const now = new Date();

const seconds = now.getSeconds();
const secondsDegrees = (seconds / 60) * 360 + 90;
secondsRef.current.style.transform = `rotate(${secondsDegrees}deg)`;

const minutes = now.getMinutes();
const minutesDegrees = (minutes / 60) * 360 + (seconds / 60) * 6 + 90;
minutesRef.current.style.transform = `rotate(${minutesDegrees}deg)`;

const hours = now.getHours();
const hoursDegrees = (hours / 12) * 360 + (minutes / 60) * 30 + 90;
hoursRef.current.style.transform = `rotate(${hoursDegrees}deg)`;
}

const intervalId = setInterval(setTime, 1000);

return () => clearInterval(intervalId);
}, []);

return (
<main>
<section>
<span ref={secondsRef}></span>
<span ref={minutesRef}></span>
<span ref={hoursRef}></span>
</section>
</main>
);
}

export default Clock;
Clock final version.
Clock final version.

Once again, the main code in JavaScript was taken from the course exercise (see link at the beginning). I then refactored it to React and made a few adjustments (like responsiveness, colors, clock hands dimensions, etc.).

Overall, this is a simple React component which can be made differently, but I just like spending a bit of time doing various coding challenges from time to time and decided to try this one today with a more or less direct approach.

[Note from the future: some adjustments to the clock are described here]

Thank you for reading.

--

--

Dimterion

Hi. I’m Dmitrii. I'm interested in Web Development and write about it every Friday.