Create a Button with a Loading Spinner in HTML & CSS 🔥
Tags: html, css, webdev, ux
Published: 2021-02-15 12:09:16

In today's post I'll be showing you how to use HTML and CSS to create an awesome looking button that features a loading spinner when clicked on.

## Source Code & Preview
If you want to follow a long with the complete source code, you can find it here.

{% codepen https://codepen.io/dcode-software/pen/abZPmRb %}

## Video Tutorial
If you prefer this tutorial in the form of a video, you can watch it on my YouTube channel, **dcode**.

Also, consider subscribing to my channel if you're interested in web development 😁

{% youtube GWw4qxF62hA %}

## HTML
Let's begin by writing the HTML for the button. This is going to be fairly straightforward. We create a `<button>` with a class of `button` and use a `<span>` for the text inside of it.

```html
<button type="button" class="button">
    <span class="button__text">Save Changes</span>
</button>
```

That's all we need for the HTML. Let's move onto the CSS 🙂

## CSS
Here's where the majority of the code is placed.

#### Styling The Button
To begin, let's style up the `.button` and `.button-text` class.

```css
.button {
    position: relative;
    padding: 8px 16px;
    background: #009579;
    border: none;
    outline: none;
    border-radius: 2px;
    cursor: pointer;
}

.button:active {
    background: #007a63;
}

.button__text {
    font: bold 20px 'Quicksand', san-serif;
    color: #ffffff;
    transition: all 0.2s;
}
```

As you may have noticed, a lot of these properties are for look and feel - but the main one to focus on here is `position: relative`.

By using `position: relative`, it means we can center the loading spinner, which we'll see shortly.

#### Creating The Spinner
We'll be using the `::after` pseudo-element to create the spinning animation. A pseudo-element is an element (like HTML) that you can style in CSS - in our case, `::after` will create a "fake element" that sits inside our `.button`.

> **Important!**
We're going to be applying CSS to a class called `.button--loading`. Basically, this is a *modifier* class on the `.button` which can be added dynamically through JavaScript whenever you want the spinning animation to appear. For example, this may be done at the time of submitting a form.

```css
.button--loading::after {
    content: "";
    position: absolute;
    width: 16px;
    height: 16px;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    border: 4px solid transparent;
    border-top-color: #ffffff;
    border-radius: 50%;
    animation: button-loading-spinner 1s ease infinite;
}
```

Let's focus on a few properties here:
* `content: "";` - this is a requirement to get the spinner to display
* `position: absolute;` - used in combination with `position: relative;` above, and the `top`, `left`, `right` and `bottom` properties will allow us to center the spinner
* `border: 4px solid transparent` - with this, we are setting a `4px` wide solid border that is transparent. Combining it with `border-top-color` will only show a border at the top of the `16x16` square. This is **key** to creating a circle spinner.
* `border-radius: 50%` - this creates the circle

I recommend you toggle some of these properties on and off, to get a full understanding of how they work to produce a circle.

As you may have noticed, we're also specifying an `animation` here, with a value of `button-loading-spinner 1s ease infinite`. This means, as long as the spinner is showing, make it spin infinitely with an `ease` timing duration, and an animation time of 1 second.

The `button-loading-spinner` animation doesn't actually exist yet, so we must create it.

#### Animation
To make the animation specified in the previous block of code above work, we need to create keyframes for it. This is simple.

```css
@keyframes button-loading-spinner {
    from {
        transform: rotate(0turn);
    }

    to {
        transform: rotate(1turn);
    }
}
```

Here, we're just saying the animation must turn our quarter-circle spinner from no turn to a full turn. With this code, the `animation` property above will now work.

## Making The Button Work
Now that we've got all the CSS done, we need to make the spinner appear using JavaScript. Typically, you'll want to activate the spinner as soon as the button is clicked on.

To do this, you simply add the class of `.button--loading`, for example:

```js
const theButton = document.querySelector(".button");

theButton.addEventListener("click", () => {
    theButton.classList.add("button--loading");
});
```

Every application is going to be different, so it's up to you to decide when to toggle the loading spinner. To remove it, you can use `classList.remove("button--loading");`.

## Conclusion
And that is how to create a button with a loading spinner using HTML and CSS. If you have any questions or comments please leave them below and I'll try my best to respond 🙂 cheers!