156

enter image description here

How would i get my cursor to change to this loading icon when a function is called and how would i change it back to a normal cursor in javascript/jquery

ahmet
  • 4,955
  • 11
  • 39
  • 64
  • 7
    if you want exactly this cursor, you need to specify an url, otherwise (with Roberts solution) every user will see the loading cursor depending on his OS. – Christoph Mar 13 '12 at 09:25
  • 1
    Christoph, what would 'wait' show for other operating systems i'm currently on windows 7, because at the moment it looks fine – ahmet Mar 13 '12 at 09:31
  • 2
    well, in vista it would show the same cursor as in windows 7, but with it's broken animation, on older Windows OS it would show the good ol' hourglass and on Linux or Mac OS it would show their respective "waiting" cursor. Also i would suggest not to manipulate the users cursor, since this is commonly associated with OS-Operations, but rather provide a little waiting-animation [like these](http://ajaxload.info/) directly on your webpage, which helps the user to see at first glance, that the waiting operation is caused by your site and not the OS. – Christoph Mar 13 '12 at 09:45
  • 1
    see also http://stackoverflow.com/questions/192900/wait-cursor-over-entire-html-page – Brian Burns Feb 07 '14 at 22:06
  • 1
    Good idea for desktop, BAD idea for mobile... – NaN Feb 23 '19 at 00:23

15 Answers15

238

In your jQuery use:

$("body").css("cursor", "progress");

and then back to normal again

$("body").css("cursor", "default");
Stanley
  • 3,935
  • 2
  • 18
  • 22
  • 11
    I used `$("html,body")` because my page's body only fit half of the window so the cursor was still default when hovering over the bottom half. – Keith Mar 13 '15 at 20:54
  • 2
    Other elements on the page (i.e. Bootstrap buttons) which override the cursor to a non-default display will block this approach while the cursor is still over the element. In those cases, I found it preferable to use `!important` with @hrabinowitz's solution below – Addison Klinke Aug 07 '20 at 14:21
  • 5
    Native JavaScript: `document.body.style.cursor = 'progress';` `document.body.style.cursor = 'default';` – Charles Fries Jan 05 '21 at 22:16
  • 1
    If you're using this approach when clicking an element which has cursor styling then you will also need to apply styling to the element itself, otherwise unless the user moves the cursor away from the element the new cursor graphic won't appear. E.g. `el.css("cursor", "progress");` and then back to normal again `el.css("cursor", "");` – nick Jan 07 '21 at 12:32
  • 1
    It doesnt work, at least in Firefox. Changing css appears after javascript finishes. I didnt find how to repaint cursor while script is running and exporer doesn't respond. – Hink Mar 25 '21 at 21:00
108

A colleague suggested an approach that I find preferable to the chosen solution here. First, in CSS, add this rule:

body.waiting * {
    cursor: progress;
}

Then, to turn on the progress cursor, say:

$('body').addClass('waiting');

and to turn off the progress cursor, say:

$('body').removeClass('waiting');

The advantage of this approach is that when you turn off the progress cursor, whatever other cursors may have been defined in your CSS will be restored. If the CSS rule is not powerful enough in precedence to overrule other CSS rules, you can add an id to the body and to the rule, or use !important.

Sam Watkins
  • 7,819
  • 3
  • 38
  • 38
hrabinowitz
  • 1,600
  • 2
  • 13
  • 12
66

Please don't use jQuery for this in 2021! There is no reason to include an entire external library just to perform this one action which can be achieved with one line:

Change cursor to spinner: document.body.style.cursor = 'wait'

Revert cursor to normal: document.body.style.cursor = 'default'

kchuang7
  • 707
  • 6
  • 7
  • 3
    Most likely there's something on that page that adds the need for a custom processing cursor, wouldn't you think? Not a bad point of course, but the change of jQuery already being loaded for something else would be... ehm... 100%? – patrick Aug 27 '18 at 11:47
  • 1
    As @ahmet asks for javascript/jquery solution, I think yours should be also the answer. +1 – Javier Nov 14 '19 at 09:21
  • @patrick: This solution is perfect for small webpages, e.g. on an Arduino. I'm happy I don't need to load jQuery on an ESP8266 just to show some waiting cursor. – Eric Duminil Dec 12 '20 at 20:52
  • 2
    Good alternative. But to categorically say "Don't use jQuery" ... is stupid. jQuery is a *PREFERRED* solution for a large *MAJORITY* of web sites. – FoggyDay May 21 '21 at 20:09
  • First is jquery did not work for me, only this one worked lol, that was silly I dint even try – Aadam Jul 18 '21 at 19:00
13

jQuery:
$("body").css("cursor", "progress");

back again
$("body").css("cursor", "default");

Pure:
document.body.style.cursor = 'progress';

back again
document.body.style.cursor = 'default';

xoxn-- 1'w3k4n
  • 496
  • 1
  • 7
  • 18
10

The following is my preferred way, and will change the cursor everytime a page is about to change i.e. beforeunload

$(window).on('beforeunload', function(){
   $('*').css("cursor", "progress");
});
shaneparsons
  • 1,489
  • 1
  • 20
  • 24
7
$('#some_id').click(function() {
  $("body").css("cursor", "progress");
  $.ajax({
    url: "test.html",
    context: document.body,
    success: function() {
      $("body").css("cursor", "default");
    }
  });
});

This will create a loading cursor till your ajax call succeeds.

Brian Burns
  • 20,575
  • 8
  • 83
  • 77
Kanishka Panamaldeniya
  • 17,302
  • 31
  • 123
  • 193
  • 1
    @Christoph, why don't you provide us an answer with the better code, please? I would definitely prefer better code always. – Bobort Jan 13 '17 at 17:36
  • @Bobort this question has a lot of decent answers already. Also it is 4 years old and meanwhile `success` and `complete` are removed in jQ3, so you have to go with `$.ajax(...).always(...);` The progess cursor could be set in the `beforeSend` function. – Christoph Jan 16 '17 at 03:32
7

Using jquery and css :

$("#element").click(function(){ 
    $(this).addClass("wait");
});​

HTML: <div id="element">Click and wait</div>​

CSS: .wait {cursor:wait}​

Demo here

tusar
  • 3,364
  • 6
  • 37
  • 60
  • This demonstrates that the wait cursor can be shown over a container that is less than the whole page - may make sense if other parts of the page can still be interacted with. Here, only while hovered over the `div`. In practice, the chosen item to show wait cursor should be larger than the item clicked on. Often, its best to show on the whole page, as in the accepted answer. – ToolmakerSteve Apr 13 '19 at 13:55
6

Override all single element

$("*").css("cursor", "progress");
  • 7
    The problem with this approach is that you would lose CSS style for selectors like :active/:hover, once the waiting is over – Ahmad Dec 08 '14 at 10:45
5

You don't need JavaScript for this. You can change the cursor to anything you want using CSS :

selector {
    cursor: url(myimage.jpg), auto;
}

See here for browser support as there are some subtle differences depending on browser

Manse
  • 37,765
  • 10
  • 83
  • 108
3

Here is something else interesting you can do. Define a function to call just before each ajax call. Also assign a function to call after each ajax call is complete. The first function will set the wait cursor and the second will clear it. They look like the following:

$(document).ajaxComplete(function(event, request, settings) {
    $('*').css('cursor', 'default');
  });

function waitCursor() {
    $('*').css('cursor', 'progress');
  }
2

Setting the cursor for 'body' will change the cursor for the background of the page but not for controls on it. For example, buttons will still have the regular cursor when hovering over them. The following is what I am using:

To set the 'wait' cursor, create a style element and insert in the head:

var css = "* { cursor: wait; !important}";
var style = document.createElement("style");
style.type = "text/css";
style.id = "mywaitcursorstyle";
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);

Then to restore the cursor, delete the style element:

var style = document.getElementById("mywaitcursorstyle");
if (style) {
  style.parentNode.removeChild(style);
}
cat_in_hat
  • 635
  • 9
  • 15
  • It's an excellent solution that works great with all the controls on the page, even without jquery. – codeDom Aug 21 '23 at 16:18
1

If it saves too fast, try this:

<style media="screen" type="text/css">
    .autosave {display: inline; padding: 0 10px; color:green; font-weight: 400; font-style: italic;}
</style>

<input type="button" value="Save" onclick="save();" />&nbsp;
<span class="autosave" style="display: none;">Saved Successfully</span>


$('span.autosave').fadeIn("80");
$('span.autosave').delay("400");
$('span.autosave').fadeOut("80");
0

I found that the only way to get the cursor to effectively reset its style back to what it had prior to being changed to the wait style was to set the original style in a style sheet or in style tags at the start of the page, set the class of the object in question to the name of the style. Then after your wait period, you set the cursor style back to an empty string, NOT "default" and it reverts back to its original value as set in your style tags or style sheet. Setting it to "default" after the wait period only changes the cursor style for every element to the style called "default" which is a pointer. It doesn't change it back to its former value.

There are two conditions to make this work. First you must set the style in a style sheet or in the header of the page with style tags, NOT as an inline style and second is to reset its style by setting the wait style back to an empty string.

David Crawford
  • 199
  • 1
  • 7
0

css:

html.wait, html.wait * { cursor: wait !important; }

on click:

onclick: "myFunction();"  //call your procedure

separate cursor change right before onclick by:

onmousedown="$('html').addClass('wait');"

at end of your function:

$('html').removeClass('wait');" //back to normal cursor

or better timeout the cursor restore at beginning of your function: (restores cursor 50ms after your function ended doing stuff)

setTimeout(function() { $('html').removeClass('wait') }, 50);

ALL TOGETHER:

<div style="cursor: pointer" onmousedown="$('html').addClass('wait');" onclick="sample('DE');">sample</div>

<script>
    function sample(c) {
        //timeout (this waits 50ms after function completed to restore cursor)
        setTimeout(function() { $('html').removeClass('wait') }, 50);
    
        //do your stuff including a calling opening a modal window
        //call ajax etc,
    
    }
</script>
user2033838
  • 153
  • 1
  • 10
0

I will describe the problem a little differently than the answers given here. A common problem is that we want to run some function, for example, to press a button, which function can take a very long time. Before starting, we want the button to get the status disabled, and this can also be seen on the screen, or we want to change the cursor or other visual features on the screen before starting the function. The problem is that if we enter a style change unnecessarily, the JavaScript will perform the function and the changes will not be reflected on the screen, until after the JavaScript completes the mentioned function, it gets someone to display something visually on the screen. For illustration, I will give an example:

function NewPageSize() {
    var e=$('#table1-pagesize");
    e.attr('disabled', true);
    console.log('page-size change event');
    $('#time').css('background-color',RGB('#ffff00'));
    let mPageSize=e.val();
    FillTable(-1, 1, mPageSize); //a function that can take a very long time 
    e.attr('disabled', false);
    $('#time').css('background-color',RGB('#ffffff'));
};

In this example, the disabled button /"e.attr('disabled', true);"/ and the color change of the "time" element to "#ffff00" are not reflected on the screen, before FillTable() .

It took me 5 days to figure out how to solve such a problem. The solution is basically very simple, but it is very poorly explains. We need to make JS think that it has nothing to do and can render the css changes to the screen. Only then do we run the function that takes longer. But how to achieve this? For this you need to receive a regular signal. WORKER is ideal for this. You install a worker that after 500 milliseconds sends like the time or whatever and displays it on the web page with some element. If it works for you, add the call to an empty procedure. In my case, it's the PROC() function.

function startWorker() {
  if(typeof(w) == "undefined") {
    w = new Worker("/js/worker.js");
  }
  w.onmessage = function(event) {
    document.getElementById("time").innerHTML = event.data;
    PROC();
  };
}

function stopWorker() { 
  w.terminate();
  w = undefined;
}

function PROC() {return;}  //empty function

Now it gets interesting. We will rewrite the empty PROC() function so that it always does what we want. First we rewrite it to make some changes to the screen ... Alfa(). Once that's done, we'll override it to run our long-running function.... Beta(). The intermediate problem is that we need to resolve the parameters to be globally accessible. For me, the gSet() and gGet() functions are used for this. That's about all, the rest should have been clear from the code.

function NewPageSize() {
    var e=$("#table1-pagesize");
    e.attr('disabled', true);
    let mPageSize=e.val();
    console.log('page-size change event');
    $('#time').css('background-color',RGB('#ffff00'));
    gSet('Beta',
    `
    FillTable(-1, 1,`+mPageSize+`); 
    $('#time').css('background-color',RGB('#ffffff'));
    var e=$("#table1-pagesize");
    e.attr('disabled', false);
    `
    );
    PROC=Alfa;  
};

function EmptyProc() {return;}

function Alfa() {
    PROC=Beta;
}

function Beta() {
    PROC=EmptyProc;
  let s=gGet('Beta');
  let arr=s.split(';'); 
    for (var i=0; i<Len(arr); i++) {
        let t=arr[i];
        if (Len(Trim(t))>1) {
      eval(t);
        }
    }
}

Of course, there is also very sophisticated code without functions: gSet(), gGet() and "eval()", but it should be enough to understand the principle.

Jan Tungli
  • 35
  • 6