DEV Community

Kelvin Wangonya
Kelvin Wangonya

Posted on • Originally published at wangonya.com

Displaying a css spinner on ajax calls with fetch api

I always have to search for how to do this or refer back to my previous code whenever I work with fetch. For a while, I've used the solution to this SO question. It's a correct solution and it works great but to be honest, I couldn't really explain very well what was going on if someone asked me to explain that piece of my code. So I thought of a simple way to do it. It's very simple really, I think I was just overthinking it. Here's how:

Setting up the HTML

<!-- this will show our spinner -->
<div id="spinner"></div> 

<!-- And this will fetch our data -->
<button onclick="fetchData()">Load data</button>
Enter fullscreen mode Exit fullscreen mode

Creating the CSS spinner

#spinner{
  visibility: hidden;
  width: 80px;
  height: 80px;

  border: 2px solid #f3f3f3;
  border-top:3px solid #f25a41;
  border-radius: 100%;

  position: absolute;
  top:0;
  bottom:0;
  left:0;
  right: 0;
  margin: auto;

  animation: spin 1s infinite linear;
}

@keyframes spin {
  from {
      transform: rotate(0deg);
  } to {
      transform: rotate(360deg);
  }
}

#spinner.show {
  visibility: visible;
}
Enter fullscreen mode Exit fullscreen mode

The spinner visibility is hidden by default. This is the element we'll manipulate in order to show and hide it as desired.

Getting things working with Javascript

I'll use the random user generator api.

const spinner = document.getElementById("spinner");

function showSpinner() {
  spinner.className = "show";
  setTimeout(() => {
    spinner.className = spinner.className.replace("show", "");
  }, 5000);
}

// function hideSpinner() {
//   spinner.className = spinner.className.replace("show", "");
// }

function loadData() {
  showSpinner()
  fetch('https://randomuser.me/api/')
  .then(response => response.json())
    .then(data => {
    // hideSpinner()
    console.log(data)
  });
}
Enter fullscreen mode Exit fullscreen mode

When showSpinner() is called, it adds a show class to the spinner element, which turns the visibility: visible as we specified in the css. To hide the spinner, the show class is removed which turns the visibility: hidden.

For demonstration purposes, I've used a timeout function and set it to 5 seconds so the spinner can load since fetching the data takes like 1 second. But ideally, you'd want to have a hideSpinner() function and call that after the data has been returned. Then, the timeout time should be increased to maybe 15 seconds since you don't want it to load forever, after which you'd show an error.

Here's the pen

Top comments (12)

Collapse
 
moopet profile image
Ben Sinclair

This is largely irrelevant to your post :), but you can replace

  spinner.className = "show";
  // ...
  spinner.className = spinner.className.replace("show", "");
Enter fullscreen mode Exit fullscreen mode

with

  spinner.classList.add('show');
  // ...
  spinner.classList.remove('show');

Enter fullscreen mode Exit fullscreen mode

which I think makes things a little easier to read and won't interfere with any existing classes.

Collapse
 
wangonya profile image
Kelvin Wangonya

Very nice. Didn't know about that 😀

Collapse
 
link2twenty profile image
Andrew Bone

Getting JavaScript to interact with CSS is a really good way to handle this.

Just for personal preference, I'd probably use the built-in hidden attribute, rather than having a show class. I'd also animate as small an area as possible by moving the spinner to a pseudo-class.

Great work 🙂

Collapse
 
codeonjim profile image
CodeOnJIm

Oh this is good! spinner is gone as the promise is resolved!

Collapse
 
banjuare_obi profile image
Obi Pascal Banjuare

Nice I love to have script on my newly develop blog site.

Collapse
 
bgadrian profile image
Adrian B.G.

You did a common mistake, to not hide the spinner at error, see promise.catch().

I know that error handling is a tabu subject in the JS ecosystem, but we should change this.

Collapse
 
wangonya profile image
Kelvin Wangonya

Didn’t know about promise.catch. I’ll check it out. Thanks!

Collapse
 
clarachaouat profile image
Clara Chaouat

Thanks a lot ! Very clear explanation

Collapse
 
shub78910 profile image
Shubham Hirakki

But then, there's a catch. How is it related to the time of loading data. As in, it will always load for 5 seconds irrespective of the actual loading time, isn't it?

Collapse
 
codeonjim profile image
CodeOnJIm

ya.he just put it there for demonstration.

Collapse
 
kasimsn profile image
Kasim ŞEN

Thank you very much bro. It's easier than I thought.

Collapse
 
bhupendra1011 profile image
bhupendra

Great .Is there a way to change the loading icon animating speed based upon the content fetched uptill now . Should spin fast if content is about to fully download