How to build a JavaScript clock

Last week, my friend Chris Ferdinandi wrote a fantastic post about creating a clock with vanilla JS. I want to show you how to do the same thing with Reef, the wonderful anti-framework he created and maintains. It’s a simple alternative to modern JavaScript frameworks like React and Vue.

The HTML

Before we do anything, let’s look at the markup I started with.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Clock</title>
    <link href="assets/css/styles.css" rel="stylesheet">
  </head>
  <body>
    <h1>Clock</h1>
    <div id="app">
      <p>Please enable JavaScript to use this clock.</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/reefjs@5/dist/reef.min.js"></script>
    <script src="assets/js/app.js"></script>
  </body>
</html>

The most important thing to note is that I added a “please enable JavaScript” message inside the #app element. If JavaScript is enabled, we change the content of the #app element so this message isn’t seen. If not, the user sees a message informing them what to do.

The CSS

Here are the styles I added.

body {
  width: 88%;
  max-width: 40em;
  margin: 1em auto;
  line-height: 1.5;
  text-align: center;
}

p {
  font-size: 1.5rem;
}

small {
  font-size: 80%;
}

I’ve centered the body element and increased its line height because the default isn’t readable or accessible enough. I’ve increased the font size of paragraph elements, and made sure side comments contained by small elements are always 80% of their parent’s font size.

The JavaScript

Immediately-invoked function expression (IIFE)

First things first, I created an immediately-invoked function expression (IIFE) to contain the rest of my code. This allows me to keep my code outside the global scope and avoid naming conflicts with other scripts. I also opted into strict mode to make my code less error-prone.

;(function () {

  "use strict";

})();

Variables

Inside my IIFE, I created my component using Reef.

// Create the component
var app = new Reef("#app", {
  data: {
    time: new Date().toLocaleString()
  },
  template: function (props) {
    return `<p>${props.time}</p>`;
  }
});

The first argument I’ve passed into the Reef contructor is the element I want to render the component into. I’ve used #app as my selector.

The second argument is an object literal containing my options. Its data property is the state/data for the component. I’ve added a time property with the current date and time as a string. To get the date and time, I called the toLocaleString() method on an instantiation of the Date() constructor.

The template property is a function which returns the markup for the component. The props parameter represents the component’s state/data stored in the data property. I’ve returned a paragraph element containing the date/time string. I used a template literal, but if you need to support IE, go with old-school string concatenation.

Functions

Next up, I created a function for updating the time property.

/**
 * Update the time property in the data
 */
var updateTime = function () {
  var time = new Date().toLocaleString();
  app.setData({ time });
};

I get a new date/time string, then use Reef’s setData() method to reactively update the state. This means that whenever I update the state, Reef will automatically update the UI for me. This is the core principle of state-based UI. You define a template for how your UI should look based on your data. When you update the data, the UI gets automatically updated to reflect the current state of the data.

Note that I’ve used a shorthand property here, another feature of ES6. Instead of writing app.setData({ time: time }), I was able to write app.setData({ time }). This only works for properties and values that have the same name. Don’t use this if you need to support IE.

Inits & Event Listeners

Finally, I initialized my app.

// Initialize the app
app.render();

// Update the time every second
window.setInterval(updateTime, 1000);

I called Reef’s render() method to run an initial render, and used my updateTime function as the callback for the setInterval() method. I set it to run every second (every 1000 milliseconds).

Wrapping up

There you have it: a simple clock built with state-based UI. I’ll be writing more articles like this, because I want to show that it’s possible to use state-based UI without the overhead of a massive, bloated framework.

Feel free to check out the demo or view the full source code on GitHub. It’s available under the MIT License ❤️


If you have questions, feedback, or any other suggestions, please do email me. I'd love to hear from you!