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.
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 😁
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.
<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.
.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.
.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 withposition: relative;
above, and thetop
,left
,right
andbottom
properties will allow us to center the spinner -
border: 4px solid transparent
- with this, we are setting a4px
wide solid border that is transparent. Combining it withborder-top-color
will only show a border at the top of the16x16
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.
@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:
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!
Top comments (7)
Nice work, Dom. 😀 This is great for buttons. How simple would it be to adopt this to links? I'd like every link on my site, when clicked, to show a spinner in the middle of the screen. I would just use an animated .gif in my case if I were able. Can this concept be universally applied to all links upon clicking? That would be sweet 😀
Thanks!
Sim
Thank you for providing this information. For three months now I've been searching the web to find a simple solution (and understanding) of to how to incorporate a spinner into a form’s submission process.
In 10 minutes, you explained in clear detail how to not only design the spinner but provide the facility to make it actionable within the submit button
A most grateful website building colleague
hello Dom,
Thanks for posting this post.
Can you please help me out how to configure the spinner such that when the button is clicked --> the spinner start --> the time consuming function starts and finishes --> spinner stop --> directed to the response page
index.html
Application Form
Name
and this is my app.py
@app.route('/' , methods=['POST', 'GET'])
def index():
if request.method == 'POST':
name = request.form['name']
#this is when i need the spinner to spin for 5 mins
#perform some time consuming stuff
time_consuming_function()
return redirect(url_for('response'))
return render_template('index.html')
Thanks for this tutorial . really its awesome .
i guess you forgot to add this in your code:
.button--loading .button__text {
visibility: hidden;
opacity: 0;
}
Hi Dom, what the font of the Save button of the title image of top?
Thanks for your tutorial!