We're live-coding on Twitch! Join us!

I was watching Disney+ the other day (Mandalorian rocks!) and I saw a neat UI for auto advancing a user to the next episode. It was a button with a countdown.

I thought "Can we make that in CSS?!" Let's go ahead and make it!

What We'll Build

Here is our countdown timer. You can use this for a number of things. Advancing a user through your UI is the main idea here.

Final CodePen: https://codepen.io/chrisoncode/pen/JjdPyer?editors=1000

The Technique

We'll be letting CSS handle the animations since CSS animations are far more performant in browsers than letting JavaScript handle the animation. The steps for creating our countdown timer look like:

  1. Create a stack of numbers
  2. Create a JavaScript interval for every second
  3. Move the stack of numbers using CSS transforms

Essential Reading: Learn React from Scratch! (2020 Edition)

The HTML

Let's start with all of our HTML. We need two buttons along with all the numbers from 10-0.

<div>
  <button class="next">
    <span class="icon">👉</span>
    Next Episode Starts in
    <span class="countdown">
      10
      <span class="numbers">
        <span>10</span>
        <span>9</span>
        <span>8</span>
        <span>7</span>
        <span>6</span>
        <span>5</span>
        <span>4</span>
        <span>3</span>
        <span>2</span>
        <span>1</span>
        <span>0</span>
      </span>
    </span>
  </button>

  <button class="reset">Reset</button>
</div>

We have added the icon with an emoji. We also have a countdown which will contain our numbers.

The reason we have the countdown div is so that we can place a 10 in there. This 10 will be responsible for providing some space in our UI for our numbers. It will have space in the document flow.

We are going to have to position our numbers absolutely, which will take them out of the document flow.

The CSS

Let's start our CSS.

Base Styles

We have some basic styling for our buttons so that they look good:

/_ button styles are here _/
button {
  background: white;
  border-radius: 5px;
  border: none;
  padding: 15px 30px;
  font-size: 24px;
  font-family: 'Muli';
  display: block;
  text-transform: uppercase;
  letter-spacing: 2px;
  cursor: pointer;
  transition: 0.3s ease all;
  line-height: 1;
  display: flex;
}

button:hover {
  background: #eee;
}

.icon {
  margin-right: 8px;
}

.reset {
  font-size: 12px;
  padding: 8px 16px;
  margin: 100px auto 0;
}

Now we'll have some good looking buttons. The next step is to start positioning our numbers so that they show up in a column.

Custom Font

We've found a custom font from fonts.google.com and added the link to our CodePen settings:

https://fonts.googleapis.com/css?family=Muli&amp;display=swap

https://i.imgur.com/Q7Kt4P7.png\]\(https://i.imgur.com/Q7Kt4P7.png

Positioning the Countdown and Numbers

Add the following to our CSS.

.countdown {
  position: relative;
  display: block;
  text-indent: -9999px;
  overflow: hidden;
  margin-left: 6px;
}

.numbers {
  position: absolute;
  top: 0;
  left: 0;
  text-align: center;
  transition: 0.3s ease transform;
  text-indent: 0;
}

We have our countdown area set to overflow: hidden so that any numbers outside of its view are not seen. All we see is one number now.

Take a look at what this looks like behind the scenes without overflow: hidden:

With overflow: hidden, all of our extra numbers are hidden from view:

Let's move onto our JavaScript.

The JavaScript

This is where the work comes in to start moving our numbers every second.

Creating Variables

Let's start by grabbing everything we need from our DOM and creating our variables.

// grab parts of our HTML
const countdownArea = document.querySelector('.countdown');
const numbersArea = document.querySelector('.numbers');
const resetBtn = document.querySelector('.reset');

// create an interval and counter
let interval;
let count = 0;

// calculate the height of our numbers
const height = countdownArea.getBoundingClientRect().height;

Creating a Timer

Next up, we'll create a function to create a timer. The things we need to do are:

  1. Increment our count
  2. Use the count and the height to figure out how far to offset the list of numbers
  3. Apply that new offset to the numbers section with CSS transforms
  4. Make sure to stop the interval once we reach 10
// create the interval that creates the timer
function createTimer() {
  interval = setInterval(() => {

        // 1. increment our count
    count++;

    // 2. calculate the offset and apply it
    const offset = height * count;

        // 3. apply the offset using css transforms
    numbersArea.style.transform = `translateY(-${offset}px)`

    // 4. stop the interval at 10
    if (count >= 10) {
      // go to the next episode
      clearInterval(interval);
    }
  }, 1000);
}

The last part is to actually call our new function. Add the following and our timer should start working!

createTimer();

Adding the Reset

The last part is to add the reset. We'll use the reset button we grabbed earlier:

resetBtn.addEventListener('click', createTimer);

We have to add three lines to our createTimer function to reset everything:

function createTimer() {
  clearInterval(interval);
  count = 0;
  numbersArea.style.transform = 'translateY(0)'

    // other code goes here...
    // interval = setInterval(() => {...
}

That's it! We now have our button!

Conclusion

Using some CSS and vanilla JavaScript, we were able to create a button that has a cool effect and gives users a little more interaction.

Be sure to check out the video walkthrough and the final CodePen. Thanks for reading!

Like this article? Follow @chrisoncode on Twitter

Host websites with a $100 credit