21

In my code I use the jQuery/CSS to set and unset the 'wait' mouse cursor with the following code:

  function setWaitCursor() {
    $('body').css('cursor', 'wait');
  }

  function setDefaultCursor() {
    $('body').css('cursor', '');
  }

I use this code to change the mouse cursor for a long operation:

setWaitCursor();

... do stuff that takes a few seconds ...

setDefaultCursor();

This code doesn't seem to work unless you move the mouse, however (at least for Chrome on Win 10). If the mouse is not moved after setDefaultCursor is called, the cursor displays the 'wait' cursor until the mouse is moved (or vice versa).

Example: https://jsfiddle.net/antonyakushin/0jv6rqkf/

In this fiddle, the cursor changes for 2 seconds after the link is clicked. If you don't move the mouse when you click the link, the cursor does not change.

What is the best way to resolve this issue, so that even if the mouse is not moved the cursor is changed?

Anton
  • 3,998
  • 25
  • 40

5 Answers5

36

Although this is not the answer to this specific problem, this behavior can happen:

  • On Chrome
  • With DevTools open (which is very likely, in order to debug this issue)

The solution is simply to close the Chrome DevTools.

philippe_b
  • 38,730
  • 7
  • 57
  • 59
  • 4
    oh my gosh, I cannot believe that was it. thanks so much! – ComradeJoecool May 21 '20 at 04:48
  • @ComradeJoecool Yep, failed by devtools... ** insert Obi-Wan "You were the chosen one" meme here ** – philippe_b May 21 '20 at 17:07
  • If closing DevTools does not seem to fix the problem for you then try closing all Chrome windows and then start a new Chrome window. That's what I had to do, and it fixes the problem until you start DevTools again. – Bob Arlof Jul 23 '20 at 20:23
  • 1
    @philippe_b salute from 2023, problem is still there and is fixed by your solution! tnx! – ermushko Apr 11 '23 at 17:09
3

Some elements have default cursor styles. So wile changing the cursor style we need to change that too.

$(document).ready(function() {
  function setWaitCursor(elem) {
    elem.css('cursor', 'wait');
    $('body').css('cursor', 'wait');
  }
  function setDefaultCursor(elem) {
    elem.css('cursor', '');
    $('body').css('cursor', '');
  }
  $('#testLink').on('click', function() {
    var x = $(this)
    setWaitCursor(x);
    setTimeout(function() {
      setDefaultCursor(x);
    }, 5000);
    return false;
  });
});

Demo fiddle

Rino Raj
  • 6,264
  • 2
  • 27
  • 42
  • 1
    I'm finding that running this type of code on page load seems to work, but not when triggered though an event such as a clicked link or button. For example, I have the issue here if the mouse if not moved when the "Test Link" is clicked: https://jsfiddle.net/antonyakushin/0jv6rqkf/ – Anton Apr 13 '16 at 12:00
  • I have updated my answer. Please verify it and let me know if you need any change. – Rino Raj Apr 13 '16 at 12:03
  • Excellent explanation, I didn't realize some elements had a default cursor style. Thanks! – Anton Apr 13 '16 at 12:30
  • Fyi this fiddle example fails on Chrome Version 58.0.3029.110 (64-bit) – PeterT May 25 '17 at 06:09
  • 2
    Still fails on Chrome 59.0.3071.115 (the cursor doesn't change to the loading indicator until you move the mouse, but it does change back without moving the mouse) – MrColes Jul 21 '17 at 19:23
2

Just change the body to *. It will be applicable to all the elements.

Fiidle Demo

Code snippets:

$(document).ready(function() {

  function setWaitCursor() {
    $('*').css('cursor', 'wait');
  }

  function setDefaultCursor() {
    $('*').css('cursor', '');
  }

  $('#testLink').on('click', function() {
    setWaitCursor();
    setTimeout(function() {
      setDefaultCursor();
    }, 2000);
    return false;
  });

});
body {
  min-width: 500px;
  min-height: 500px;
  background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div id="mouseContainer">
  <a href="#" id="testLink">Test Link</a>
</div>
John R
  • 2,741
  • 2
  • 13
  • 32
2

I think I solved it! Just call setTimeout() after you change the cursor. For example

$('body').addClass('in-progress-cursor');
setTimeout(null, 0); //in typescript we need to provide arguments

This is well-known trick (Why is setTimeout(fn, 0) sometimes useful?) but I didn't expect this would work in this case.

This is my favorite method of telling user unobtrusively that there is something going on. For example I use it to indicate that http requests are in progress. It is such a relief that the solution is found. Why I feel stupid again... Actually I see the timeout in John R's answer now. But it is not evident enough.

alehro
  • 2,198
  • 2
  • 25
  • 41
1

I had the same problem and I noticed on another post cursor won't change until mouse moves that they had suggested doing a blur and focus to fix this. It worked for me. So, your setWaitCursor() should look something like this. That should force it to change without the mouse move. It worked for me in Chrome, but haven't tried other browsers.

  function setWaitCursor(elem) {
    elem.css('cursor', 'wait');
    $('body').css('cursor', 'wait');
    window.blur();
    window.focus();
  }
Jeff R.
  • 188
  • 7
  • to be fair to the topic, there are a lot of edge conditions. I did something similar when unloading pages for page transition, but if you are a perfectionist, you might worry about doing a page back, page reload (keyboard or mouse), transition when hovering over something else that might change the cursor (e.g. a link), etc. – Jeff R. Apr 10 '19 at 17:44