How to add a spinner icon to button when it's in the Loading state?

ButtonTwitter BootstrapIconsLoadingFont Awesome

Button Problem Overview


Twitter Bootstrap's buttons have a nice Loading... state available.

The thing is that it just shows a message like Loading... passed through the data-loading-text attribute like this:

<button type="button" class="btn btn-primary start" id="btnStartUploads"
        data-loading-text="@Localization.Uploading">
    <i class="icon-upload icon-large"></i>
    <span>@Localization.StartUpload</span>
</button>

Looking at Font Awesome, you see that there's now an animated spinner icon.

I tried to integrate that spinner icon when firing an Upload operation like this:

$("#btnStartUploads").button('loading');
$("#btnStartUploads i").removeAttr('class');
$("#btnStartUploads i").addClass('icon-spinner icon-spin icon-large');

but this had no effect at all, that is, I just see the Uploading... text on the button.

Is it possible to add an icon when the button is in the Loading state? Looks like somehow Bootstrap just removes the icon <i class="icon-upload icon-large"></i> inside the button while in the Loading state.


Here's a simple demo that shows the behavior I describe above. As you see when it enters the Loading state the icon just disappears. It reappears right after the time interval.

Button Solutions


Solution 1 - Button

Simple solution for Bootstrap 3 using CSS3 animations.

Put the following in your CSS:

.glyphicon.spinning {
    animation: spin 1s infinite linear;
    -webkit-animation: spin2 1s infinite linear;
}

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

@-webkit-keyframes spin2 {
    from { -webkit-transform: rotate(0deg); }
    to { -webkit-transform: rotate(360deg); }
}

Then just add the spinning class to a glyphicon while loading to get your spinning icon:

<button class="btn btn-lg btn-warning">
    <span class="glyphicon glyphicon-refresh spinning"></span> Loading...    
</button>

Based on http://www.bootply.com/128062#

  • Note: IE9 and below do not support CSS3 animations.

Solution 2 - Button

If you look at the bootstrap-button.js source, you'll see that the bootstrap plugin replaces the buttons inner html with whatever is in data-loading-text when calling $(myElem).button('loading').

For your case, I think you should just be able to do this:

<button type="button"
        class="btn btn-primary start"
        id="btnStartUploads"
        data-loading-text="<i class='icon-spinner icon-spin icon-large'></i> @Localization.Uploading">
    <i class="icon-upload icon-large"></i>
    <span>@Localization.StartUpload</span>
</button>

Solution 3 - Button

There's now a full-fledged plugin for that:

http://msurguy.github.io/ladda-bootstrap/

Solution 4 - Button

To make the solution by @flion look really great, you could adjust the center point for that icon so it doesn't wobble up and down. This looks right for me at a small font size:

.glyphicon-refresh.spinning {
  transform-origin: 48% 50%;
}

Solution 5 - Button

A lazy way to do this is with the UTF-8 entity code for a half circle \25E0 (aka &#x25e0;), which looks like ◠ and then keyframe animate it. It's a simple as:

.busy { animation: spin 1s infinite linear; display:inline-block; font-weight: bold; font-family: sans-serif; font-size: 35px; font-style:normal; color:#555; }

.busy::before { content:"\25E0"; }

@keyframes spin { 0% {transform: rotate(0deg);} 100% {transform: rotate(359deg);} }

Solution 6 - Button

Here's my solution for Bootstrap 4:

<button id="search" class="btn btn-primary" 
data-loading-text="<i class='fa fa-spinner fa-spin fa-fw' aria-hidden='true'></i>Searching">
  Search
</button>

var setLoading = function () {
  var search = $('#search');
  if (!search.data('normal-text')) {
    search.data('normal-text', search.html());
  }
  search.html(search.data('loading-text'));
};

var clearLoading = function () {
  var search = $('#search');
  search.html(search.data('normal-text'));
};

setInterval(() => {
  setLoading();
  setTimeout(() => {
    clearLoading();
  }, 1000);
}, 2000);

Check it out on JSFiddle

Solution 7 - Button

These are mine, based on pure SVG and CSS animations. Don't pay attention to JS code in the snippet bellow, it's just for demoing purposes. Feel free to make your custom ones basing on mine, it's super easy.

var svg = d3.select("svg"),
    columnsCount = 3;

['basic', 'basic2', 'basic3', 'basic4', 'loading', 'loading2', 'spin', 'chrome', 'chrome2', 'flower', 'flower2', 'backstreet_boys'].forEach(function(animation, i){
  var x = (i%columnsCount+1) * 200-100,
      y = 20 + (Math.floor(i/columnsCount) * 200);
  
  
  svg.append("text")
    .attr('text-anchor', 'middle')
    .attr("x", x)
    .attr("y", y)
    .text((i+1)+". "+animation);
  
  svg.append("circle")
    .attr("class", animation)
    .attr("cx",  x)
    .attr("cy",  y+40)
    .attr("r",  16)
});

circle {
  fill: none;
  stroke: #bbb;
  stroke-width: 4
}

.basic {
  animation: basic 0.5s linear infinite;
  stroke-dasharray: 20 80;
}

@keyframes basic {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.basic2 {
  animation: basic2 0.5s linear infinite;
  stroke-dasharray: 80 20;
}

@keyframes basic2 {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.basic3 {
  animation: basic3 0.5s linear infinite;
  stroke-dasharray: 20 30;
}

@keyframes basic3 {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.basic4 {
  animation: basic4 0.5s linear infinite;
  stroke-dasharray: 10 23.3;
}

@keyframes basic4 {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.loading {
  animation: loading 1s linear infinite;
  stroke-dashoffset: 25;
}

@keyframes loading {
  0%    {stroke-dashoffset: 0;    stroke-dasharray: 50 0; }
  50%   {stroke-dashoffset: -100; stroke-dasharray: 0 50;}
  100%  { stroke-dashoffset: -200;stroke-dasharray: 50 0;}
}

.loading2 {
  animation: loading2 1s linear infinite;
}

@keyframes loading2 {
  0% {stroke-dasharray: 5 28.3;   stroke-dashoffset: 75;}
  50% {stroke-dasharray: 45 5;    stroke-dashoffset: -50;}
  100% {stroke-dasharray: 5 28.3; stroke-dashoffset: -125; }
}

.spin {
  animation: spin 1s linear infinite;
  stroke-dashoffset: 25;
}

@keyframes spin {
  0%    {stroke-dashoffset: 0;    stroke-dasharray: 33.3 0; }
  50%   {stroke-dashoffset: -100; stroke-dasharray: 0 33.3;}
  100%  { stroke-dashoffset: -200;stroke-dasharray: 33.3 0;}
}

.chrome {
  animation: chrome 2s linear infinite;
}

@keyframes chrome {
  0%    {stroke-dasharray: 0 100; stroke-dashoffset: 25;}
  25%   {stroke-dasharray: 75 25; stroke-dashoffset: 0;}
  50%   {stroke-dasharray: 0 100;  stroke-dashoffset: -125;}
  75%    {stroke-dasharray: 75 25; stroke-dashoffset: -150;}
  100%   {stroke-dasharray: 0 100; stroke-dashoffset: -275;}
}

.chrome2 {
  animation: chrome2 1s linear infinite;
}

@keyframes chrome2 {
  0%    {stroke-dasharray: 0 100; stroke-dashoffset: 25;}
  25%   {stroke-dasharray: 50 50; stroke-dashoffset: 0;}
  50%   {stroke-dasharray: 0 100;  stroke-dashoffset: -50;}
  75%   {stroke-dasharray: 50 50;  stroke-dashoffset: -125;}
  100%  {stroke-dasharray: 0 100;  stroke-dashoffset: -175;}
}

.flower {
  animation: flower 1s linear infinite;
}

@keyframes flower {
  0%    {stroke-dasharray: 0  20; stroke-dashoffset: 25;}
  50%   {stroke-dasharray: 20 0;  stroke-dashoffset: -50;}
  100%  {stroke-dasharray: 0 20;  stroke-dashoffset: -125;}
}

.flower2 {
  animation: flower2 1s linear infinite;
}

@keyframes flower2 {
  0%    {stroke-dasharray: 5 20;  stroke-dashoffset: 25;}
  50%   {stroke-dasharray: 20 5;  stroke-dashoffset: -50;}
  100%  {stroke-dasharray: 5 20;  stroke-dashoffset: -125;}
}

.backstreet_boys {
  animation: backstreet_boys 3s linear infinite;
}

@keyframes backstreet_boys {
  0%    {stroke-dasharray: 5 28.3;  stroke-dashoffset: -225;}
  15%    {stroke-dasharray: 5 28.3;  stroke-dashoffset: -300;}
  30%   {stroke-dasharray: 5 20;  stroke-dashoffset: -300;}
  45%    {stroke-dasharray: 5 20;  stroke-dashoffset: -375;}
  60%   {stroke-dasharray: 5 15;  stroke-dashoffset: -375;}
  75%    {stroke-dasharray: 5 15;  stroke-dashoffset: -450;}
  90%   {stroke-dasharray: 5 15;  stroke-dashoffset: -525;}
  100%   {stroke-dasharray: 5 28.3;  stroke-dashoffset: -925;}
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="600px" height="700px"></svg>

Also available on CodePen: https://codepen.io/anon/pen/PeRazr

Solution 8 - Button

Here is a full-fledged css solution inspired by Bulma. Just add

    .button {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      position: relative;
      min-width: 200px;
      max-width: 100%;
      min-height: 40px;
      text-align: center;
      cursor: pointer;
    }
    
    @-webkit-keyframes spinAround {
      from {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      to {
        -webkit-transform: rotate(359deg);
        transform: rotate(359deg);
      }
    }
    @keyframes spinAround {
      from {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      to {
        -webkit-transform: rotate(359deg);
        transform: rotate(359deg);
      }
    }
    
    .button.is-loading {
      text-indent: -9999px;
      box-shadow: none;
      font-size: 1rem;
      height: 2.25em;
      line-height: 1.5;
      vertical-align: top;
      padding-bottom: calc(0.375em - 1px);
      padding-left: 0.75em;
      padding-right: 0.75em;
      padding-top: calc(0.375em - 1px);
      white-space: nowrap;
    }
    
    .button.is-loading::after  {
      -webkit-animation: spinAround 500ms infinite linear;
      animation: spinAround 500ms infinite linear;
      border: 2px solid #dbdbdb;
      border-radius: 290486px;
      border-right-color: transparent;
      border-top-color: transparent;
      content: "";
      display: block;
      height: 1em;
      position: relative;
      width: 1em;
    }

Solution 9 - Button

The only thing I found that worked was a post here: https://stackoverflow.com/a/44548729/9488229

I improved it, and now it provides all these features:

  • Disable the button after click
  • Show an animated loading icon using native bootstrap
  • Re-enable the button after the page is done loading
  • Text goes back to original when page loading is done

Javascript:

$(document).ready(function () {
    $('.btn').on('click', function() {
        var e=this;
        setTimeout(function() {
            e.innerHTML='<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Searching...';
            e.disabled=true;
        },0);
        return true;
    });
});

Solution 10 - Button

You can use the Bootstrap spinner. Use "position: absolute" to make both buttons over each other. With the JavaScript code you can remove the front button and the back button will be displayed.

        button {
            position: absolute;
            top: 50px;
            left: 150px;
            width: 150px;
            font-size: 120%;
            padding: 5px;
            background: #B52519;
            color: #EAEAEA;
            border: none;
            margin: 120px;
            border-radius: 5px;
            display: flex;
            align-content: center;
            justify-content: center;
            transition: all 0.5s;
            height: 40px
        }

        #orderButton:hover {
            color: #c8c8c8;
        }

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

<button><div class="spinner-border"></div></button>
<button id="orderButton" onclick="this.style.display= 'none';">Order!</button>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeniel MaccaferriView Question on Stackoverflow
Solution 1 - ButtonFlionView Answer on Stackoverflow
Solution 2 - Buttongurch101View Answer on Stackoverflow
Solution 3 - ButtonraverenView Answer on Stackoverflow
Solution 4 - ButtonjakeView Answer on Stackoverflow
Solution 5 - ButtonVolomikeView Answer on Stackoverflow
Solution 6 - ButtonmikemsqView Answer on Stackoverflow
Solution 7 - ButtonDamianoView Answer on Stackoverflow
Solution 8 - ButtonBrendan WeinsteinView Answer on Stackoverflow
Solution 9 - ButtonColinView Answer on Stackoverflow
Solution 10 - ButtonGucciBananaKing99View Answer on Stackoverflow