Salesforce-style spinner for use on CloudPages

Spinners are loading indicators that can be shown when retrieving data or performing other operations.

We will use a common spinner that Salesforce Lightening users are familiar with – the full documentation can be found here. This spinner is a Lightning component, which means that it cannot be directly used on a CloudPage. My awesome colleague Anna rewrote it into HTML and CSS, so that it can be easily copied and pasted for use on a CloudPage. This way, you can emulate the look and feel of other Salesforce clouds on your CloudPages.

It doesn’t necessarily add any value for external users of your CloudPages, but it can improve the experience of Salesforce Marketing Cloud users who internally use apps created on CloudPages and are familiar with other Salesforce clouds.

Here’s a preview of the spinner we will create in a few easy steps:

Let’s start with adding the CSS for our spinner. You can paste below code anywhere in your existing style-sheet, or create a separate one and link to it in the document head:

.slds-spinner_container{position:absolute;top:0;right:0;bottom:0;left:0;z-index:9050;background-color:hsla(0,0%,100%,.75);visibility:visible;opacity:1;transition:opacity .2s ease,visibility 0;transition-delay:0s,.3s;display:none}
.slds-spinner{position:absolute;top:50%;left:50%;z-index:9051;transform:translate(-50%,-50%) rotate(90deg)}
.slds-spinner,.slds-spinner__dot-a,.slds-spinner__dot-b{transform-origin:50% 50%;will-change:transform}
.slds-spinner__dot-a,.slds-spinner__dot-b{position:absolute;top:0;left:0;width:100%}
.slds-spinner:after,.slds-spinner:before,.slds-spinner__dot-a:after,.slds-spinner__dot-a:before,.slds-spinner__dot-b:after,.slds-spinner__dot-b:before{content:"";position:absolute;background:#b0adab;border-radius:50%;animation-duration:1s;animation-iteration-count:infinite;transform:translateZ(0)}
.slds-spinner__dot-a{transform:rotate(60deg)}
.slds-spinner__dot-b{transform:rotate(120deg)}
.slds-spinner:before{animation-delay:-.083s}
.slds-spinner__dot-a:before{animation-delay:.083s}
.slds-spinner__dot-b:before{animation-delay:.25s}
.slds-spinner:after{animation-delay:.41666667s}
.slds-spinner__dot-a:after{animation-delay:.583s}
.slds-spinner__dot-b:after{animation-delay:.75s}
@keyframes dotsBounceBefore-medium {
0%{transform:translateZ(0)}
60%{transform:translateZ(0);animation-timing-function:cubic-bezier(.55,.085,.68,.53)}
80%{transform:translate3d(-.5rem,0,0);animation-timing-function:cubic-bezier(0,1.11,.7,1.43)}
to{transform:translateZ(0)}
}
@keyframes dotsBounceAfter-medium {
0%{transform:translateZ(0)}
60%{transform:translateZ(0);animation-timing-function:cubic-bezier(.55,.085,.68,.53)}
80%{transform:translate3d(.5rem,0,0);animation-timing-function:cubic-bezier(0,1.11,.7,1.43)}
to{transform:translateX(0)}
}
.slds-spinner–large,.slds-spinner_large{width:2.75rem}
.slds-spinner–large .slds-spinner__dot-a:after,.slds-spinner–large .slds-spinner__dot-a:before,.slds-spinner–large .slds-spinner__dot-b:after,.slds-spinner–large .slds-spinner__dot-b:before,.slds-spinner–large.slds-spinner:after,.slds-spinner–large.slds-spinner:before,.slds-spinner_large .slds-spinner__dot-a:after,.slds-spinner_large .slds-spinner__dot-a:before,.slds-spinner_large .slds-spinner__dot-b:after,.slds-spinner_large .slds-spinner__dot-b:before,.slds-spinner_large.slds-spinner:after,.slds-spinner_large.slds-spinner:before{width:.625rem;height:.625rem}
.slds-spinner–large .slds-spinner__dot-a:before,.slds-spinner–large .slds-spinner__dot-b:before,.slds-spinner–large.slds-spinner:before,.slds-spinner_large .slds-spinner__dot-a:before,.slds-spinner_large .slds-spinner__dot-b:before,.slds-spinner_large.slds-spinner:before{animation-name:dotsBounceBefore-medium;top:-.3125rem;left:-.3125rem}
.slds-spinner–large .slds-spinner__dot-a:after,.slds-spinner–large .slds-spinner__dot-b:after,.slds-spinner–large.slds-spinner:after,.slds-spinner_large .slds-spinner__dot-a:after,.slds-spinner_large .slds-spinner__dot-b:after,.slds-spinner_large.slds-spinner:after{animation-name:dotsBounceAfter-medium;top:-.3125rem;right:-.3125rem}
@keyframes dotsBounceBefore-large {
0%{transform:translateZ(0)}
60%{transform:translateZ(0);animation-timing-function:cubic-bezier(.55,.085,.68,.53)}
80%{transform:translate3d(-.75rem,0,0);animation-timing-function:cubic-bezier(0,1.11,.7,1.43)}
to{transform:translateX(0)}
}
@keyframes dotsBounceAfter-large {
0%{transform:translateZ(0)}
60%{transform:translateZ(0);animation-timing-function:cubic-bezier(.55,.085,.68,.53)}
80%{transform:translate3d(.75rem,0,0);animation-timing-function:cubic-bezier(0,1.11,.7,1.43)}
to{transform:translateX(0)}
}
view raw spinner-styles.css hosted with ❤ by GitHub

Now let’s add our spinner to the CloudPage. We will create an HTML button and add an onclick event, so that the spinner activates once the user clicks the button:

<button onClick="showSpinner()">Try me!</button>
<div class="slds-spinner_container">
<div role="status" class="slds-spinner slds-spinner_large"><span class="slds-assistive-text"></span>
<div class="slds-spinner__dot-a"></div>
<div class="slds-spinner__dot-b"></div>
</div>
</div>
view raw spinner-html.html hosted with ❤ by GitHub

And finally, let’s add the script with the showSpinner() function:

<script>
function showSpinner() {
$spinner = document.getElementsByClassName("slds-spinner_container")[0];
$spinner.style.display = "block";
}
</script>
view raw spinner-js.html hosted with ❤ by GitHub

Above function will activate the spinner once the button is clicked and it will run indefinitely, which means that it’s appropriate for any use cases where the website gets reloaded or redirected to another one after all operations have been completed.

If you would like to control for how long the spinner is displayed, you can use the setTimeout method to deactivate the spinner after a given time. Below script will hide the spinner after 5 seconds:

<script>
function showSpinner() {
$spinner = document.getElementsByClassName("slds-spinner_container")[0];
$spinner.style.display = "block";
setTimeout(() => {
$spinner.style.display = "none";
}, 5000);
}
</script>

You can also control the activation/deactivation of the spinner by adding a hideSpinner() function to other functions used for performing operations. Below example will post data to another website using the fetch method and hide the spinner after the operation is complete:

<script>
function showSpinner() {
$spinner = document.getElementsByClassName("slds-spinner_container")[0];
$spinner.style.display = "block";
}
function hideSpinner() {
$spinner.style.display = "none";
}
...
function postData() {
fetch("http://example.com/myData.json&quot;, {
method: "POST",
headers: {
},
body: ({
})
}).then(function(res) {
hideSpinner(), window.alert("Success")
}).catch(function(err) {
hideSpinner(), window.alert("Error")
})
}
</script>
view raw hideSpinner.html hosted with ❤ by GitHub

To see the spinner in action, visit my demo CloudPage: https://pub.s10.exacttarget.com/c5luwxbwtxa.


Questions? Comments?

Leave a comment below or email me at zuzanna@sfmarketing.cloud.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s