<main>
<h2>Submit Button with Pure CSS Loading Spinner</h2>
<p>The submit button below will enable a loading spinner when clicked. The button will be disabled while the loading spinner is present. The JavaScript mimics an asyncronous action using <code>setTimeout()</code> but this would be replaced by something else in your site/app code.</p>
<form onsubmit="return false;">
<fieldset>
<p><label for="un">Username: </label><input id="um"></p>
<p><label for="pa">Password: </label><input id="pa" type="password"></p>
<button>SUBMIT FORM<span class="spinner"></span></button>
</fieldset>
</form>
</main>
/* This is the submit button styles */
button {
display: block;
margin: 0 auto;
padding: .6em .8em;
/* Font-size is the root value that determines size of spinner parts. Change this to whatever you want and spinner elements will size to match. */
font-size: 20px;
font-weight: bold;
border-radius: .4em;
border: none;
overflow: hidden;
cursor: pointer;
position: relative;
transition: all 1s;
}
/* focus/disabled styles, you can change this for accessibility */
button:focus, button:disabled {
outline: none;
background: #aaa;
}
/* This is the space for the spinner to appear, applied to the button */
.spin {
padding-left: 2.5em;
display: block;
}
/* position of the spinner when it appears, you might have to change these values */
.spin .spinner {
left: -.6em;
top: .4em;
width: 2.5em;
display: block;
position: absolute;
}
/* spinner animation */
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* The actual spinner element is a pseudo-element */
.spin .spinner::before {
content: "";
width: 1.5em; /* Size of the spinner */
height: 1.5em; /* Change as desired */
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
border: solid .35em #999; /* Thickness/color of spinner track */
border-bottom-color: #555; /* Color of variant spinner piece */
animation: .8s linear infinite spinner; /* speed of spinner */
transform: translate(-50%, -50%);
will-change: transform;
}
/* optional, but it will affect the size if changed */
*, *::before, *::after {
box-sizing: border-box;
}
/* generic document styles below */
body {
font-family: Arial, sans-serif;
font-size: 20px;
padding: 0 20px;
}
main {
text-align: center;
margin: 0 auto;
max-width: 800px;
}
p {
text-align: left;
padding: 0 20px;
}
form p {
text-align: center;
}
fieldset {
border-radius: 10px;
}
code {
color: firebrick;
}
let btn = document.querySelector('button');
btn.addEventListener('click', function () {
// form submission starts
// button is disabled
btn.classList.add('spin');
btn.disabled = true;
// This disables the whole form via the fieldset
btn.form.firstElementChild.disabled = true;
// this setTimeout call mimics some asyncronous action
// you would have something else here
window.setTimeout(function () {
// when asyncronous action is done, remove the spinner
// re-enable button/fieldset
btn.classList.remove('spin');
btn.disabled = false;
btn.form.firstElementChild.disabled = false;
}, 4000);
}, false);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.