Preventing scroll when using URI hash to identify tab
Asked Answered
R

8

12

I'm using JQuery UI to make tabs in my application. I needed the tabs to be linkable (direct link that opens the page and selects the correct tab). This is done by using a hash tag/fragmented identifier. But I have a issue when the content above the tabs and inside the tabs is very long.

When clicking the tabs, the page scrolls down to the start of the tab. This is not what I want.

I'm using Jquery 1.7.1 and Jquery UI 1.8.16.

The javascript/Jquery code is a standard Jquery UI tabs with the addition to the event "tabsshow". This is suggested in Changing location.hash with jquery ui tabs (Stackoverflow question) and JQuery UI Tabs: Updating URL with hash while clicking the tab (blog - Tech Diary by Robin)

$(document).ready(function() {
    $("#tabs").tabs();

    /**
     * Add hash to URL of the current page
     * 
     * http://chwang.blogspot.com/2010/02/jquery-ui-tabs-updating-url-with-hash.html
     * https://mcmap.net/q/360432/-changing-location-hash-with-jquery-ui-tabs
     */
    $("#tabs").bind('tabsshow',function(event, ui) {
        window.location.hash = ui.tab.hash;
    });
});

The following HTML can be used to test the behavior

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>
<div style="height: 400px;">Some other content</div>
<div id="tabs" class="ui-tabs ui-widget ui-widget-content ui-corner-all">
    <ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
        <li class="ui-state-default ui-corner-top"><a href="#tab_1"><span>Tab 1</span></a></li>
        <li class="ui-state-default ui-corner-top"><a href="#tab_100"><span>Tab 100</span></a></li>
        <li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active"><a href="#tab_1000"><span>Tab 1000</span></a></li>
    </ul>

    <div id="tab_1" class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide">
        <table style="height: 1000px"><tr><td>Hello. This is tab 1</td></tr></table>
    </div>


    <div id="tab_100" class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide">
        <table style="height: 1000px"><tr><td>Hello. This is tab 100.</td></tr></table>
    </div>


    <div id="tab_1000" class="ui-tabs-panel ui-widget-content ui-corner-bottom"><h2>Heading</h2>
        <table style="height: 1000px"><tr><td>Hello. This is tab 1000.</td></tr></table>
    </div>
</div>

When opening the page with the following URL, one should have tab 1 opened and not scroll down to where the tab starts. The same goes for clicking on one of the tabs.

file.html#tab_1
Rida answered 24/12, 2011 at 12:31 Comment(2)
possible duplicate of JQuery UI Tabs Causing Screen to "Jump"Staciestack
Not the exact same but very similar.Rida
S
5

This may not be the best method, but if you rename all of the ID's after the tabs have been created, then adding a hash with the original ID won't scroll the page. I used this method because even with javascript disabled, the hash will take the user to the correct ID. Here is a demo of the code below:

$("#tabs").tabs({
    create: function(event, ui) {
        // get tab plugin data
        var tabs = $('#tabs').data('tabs'),
            // tabs.anchors contains all of the tab anchors
            links = tabs.anchors;
        // tabs.panels contains each tab
        tabs.panels.each(function(i){
            // just adding a "mod_" prefix to every ID/hash
            this.id = 'mod_' + this.id;
            links[i].hash = '#' + this.id;
        });
    }
});

/**
 * Add hash to URL of the current page
 * 
 * http://chwang.blogspot.com/2010/02/jquery-ui-tabs-updating-url-with-hash.html
 * https://mcmap.net/q/360432/-changing-location-hash-with-jquery-ui-tabs
 */
$("#tabs").bind('tabsshow', function(event, ui) {
    // remove the prefix from the ID, so we're showing the original ID in the hash
    window.location.hash = ui.tab.hash.replace('mod_', '');
});
Showoff answered 24/12, 2011 at 15:45 Comment(0)
D
5

As others have mentioned the code from @Mottie might have once worked on older versions of jQuery UI, but this has definitely stopped working. The jQuery UI Tabs api has changed quite a bit since that was written so here is an updated version that works with at least jQuery 1.10.2

Demo here: http://jsfiddle.net/xsx5u5g2/

var $tabs = $("#tabs");
$tabs.tabs({
  create: function(event, ui) {
    // Adjust hashes to not affect URL when clicked.
    var widget = $tabs.data("uiTabs");
    widget.panels.each(function(i){
      this.id = "uiTab_" + this.id; // Prepend a custom string to tab id.
      widget.anchors[i].hash = "#" + this.id;
      $(widget.tabs[i]).attr("aria-controls", this.id);
    });
  },
  activate: function(event, ui) {
    // Add the original "clean" tab id to the URL hash.
    window.location.hash = ui.newPanel.attr("id").replace("uiTab_", "");
  },
});
Drudge answered 29/8, 2014 at 22:21 Comment(1)
I made one modification to this. I don't want the ID renaming to happen on pageload/create. I want it to happen when the user first clicks on a tab. This ensures that bookmarked URLs work as normal. I split the ID renaming into a separate function, then wrapped that into a 'run only once' construct and added it as the first line inside 'activate'. davidwalsh.name/javascript-onceRollet
H
5

I'm using jQuery 1.11.1. This workes nicely for me.

$("#tabs").tabs(); //initialize tabs
$(function() {
    $("#tabs").tabs({
        activate: function(event, ui) {
            var scrollTop = $(window).scrollTop(); // save current scroll position
            window.location.hash = ui.newPanel.attr('id'); // add hash to url
            $(window).scrollTop(scrollTop); // keep scroll at current position
        }
    });
});

jQuery UI tabs, update url when clicking on a different tab

Thanks to Jeff B for pointing me here http://jsfiddle.net/jtbowden/ZsUBz/44/

Housetop answered 23/1, 2015 at 19:21 Comment(1)
Works Pefectly for me as well. For jQuery version 1.12.4. Thanks!Highgrade
S
1

You have to change the window hash without scrolling the page. Here is already a question on SO - Modifying document.location.hash without page scrolling.

The changes required are:

$("#tabs").bind('tabsshow',function(event, ui) {
    setHashWithoutScroll(ui.tab.hash);
});

The setHashWithoutScroll function can be taken from the above mentioned link.

function setHashWithoutScroll(hash) {
    hash = hash.replace( /^#/, '' );
    var fx, node = $( '#' + hash );
    if ( node.length ) {
      node.attr( 'id', '' );
      fx = $( '<div></div>' )
              .css({
                  position:'absolute',
                  visibility:'hidden',
                  top: $(document).scrollTop() + 'px'
              })
              .attr( 'id', hash )
              .appendTo( document.body );
    }
    document.location.hash = hash;
    if ( node.length ) {
      fx.remove();
      node.attr( 'id', hash );
    }
}

The accepted answer throws an error to me - jQuery UI Tabs: Mismatching fragment identifier. So I had to use this one.

Soukup answered 16/1, 2013 at 14:8 Comment(1)
That doesn't fix inbound links with "#tab-id" loading the page scrolled part-way downOpprobrious
O
0

I just added the following to my javascript:

    $('#tabs').tabs();
    // Direct links to the tabs, e.g. /my-page#tab-id can cause browsers
    // to scroll down to half-way down the page, which is ugly. We override that here.
    // (This can cause a brief FOUC effect where the page first displays then scrolls up)
    window.scrollTop = '0';
    window.scrollTo(0,0);

In MSIE, I get a brief FOUC effect as the page loads scrolled part-way-down, then flicks to the top.

In Firefox, this works fine without any visible FOUC.

In Chrome, this doesn't work at all -- see scrollTop does not work in Chrome, nor do suggested workarounds

Opprobrious answered 3/5, 2013 at 10:19 Comment(0)
A
0

This simple method worked for me:

/* Prevent scroll to tab on click */
$(document).ready(function(){
  $("a.ui-tabs-anchor").click(function(e){
      e.preventDefault();
      return false;
  });
});
Autocrat answered 8/2, 2015 at 23:14 Comment(0)
B
-1

I tried @mottie solution but is not working now (2 years after).
It triggers an error: TypeError: tabs is undefined.

Following is an acceptable solution for me:

// preventing scroll
// $("#tabs li a[href^='#tab']").bind('click',function(e){ // less general but better
$("#tabs li a").bind('click',function(e){
    $("html, body").animate({ scrollTop: 0 });
});
Brownstone answered 21/11, 2013 at 23:2 Comment(0)
A
-1

There are many answers on this page, and in my mind, most are overcomplicating a simple issue.

Basically, the solution from david-thomas is the simplest and most effective. Essentially, all you want to be doing is preventing the default link behaviour on a tab link (<a> tag).

The same answer applies to the bootstrap tabs, where you have to specify the click handler

   $('.nav-tabs a').click(function(e){
        e.preventDefault();
        $(this).tab('show');
    });
Aforetime answered 15/11, 2015 at 8:41 Comment(1)
Thank you for your insightful and helpful comment. I am sorry my answer made your application topple from its lofty heights...Aforetime

© 2022 - 2024 — McMap. All rights reserved.