How can I update window.location.hash without jumping the document?

Cheap and nasty solution.. Use the ugly #! style.

To set it:

window.location.hash = '#!' + id;

To read it:

id = window.location.hash.replace(/^#!/, '');

Since it doesn't match and anchor or id in the page, it won't jump.


The problem is you are setting the window.location.hash to an element's ID attribute. It is the expected behavior for the browser to jump to that element, regardless of whether you "preventDefault()" or not.

One way to get around this is to prefix the hash with an arbitrary value like so:

window.location.hash = 'panel-' + id.replace('#', '');

Then, all you need to do is to check for the prefixed hash on page load. As an added bonus, you can even smooth scroll to it since you are now in control of the hash value...

$(function(){
    var h = window.location.hash.replace('panel-', '');
    if (h) {
        $('#slider').scrollTo(h, 800);
    }
});

If you need this to work at all times (and not just on the initial page load), you can use a function to monitor changes to the hash value and jump to the correct element on-the-fly:

var foundHash;
setInterval(function() {
    var h = window.location.hash.replace('panel-', '');
    if (h && h !== foundHash) {
        $('#slider').scrollTo(h, 800);
        foundHash = h;
    }
}, 100);

There is a workaround by using the history API on modern browsers with fallback on old ones:

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}

Credit goes to Lea Verou