87

I'm currently using tabs with Twitter Bootstrap and want to select the same tab after a user has posted data and the page reloads.

How is this done?

My current call to inti the tabs looks like this:

<script type="text/javascript">

$(document).ready(function() {

    $('#profileTabs a:first').tab('show');
});
</script>

My tabs:

<ul id="profileTabs" class="nav nav-tabs">
    <li class="active"><a href="#profile" data-toggle="tab">Profile</a></li>
    <li><a href="#about" data-toggle="tab">About Me</a></li>
    <li><a href="#match" data-toggle="tab">My Match</a></li>
</ul>
Paul
  • 11,671
  • 32
  • 91
  • 143
  • 1
    This seems to be a duplicate question to http://stackoverflow.com/questions/18999501/bootstrap-3-keep-selected-tab-on-page-refresh/19015027#19015027 – koppor Apr 11 '14 at 09:49
  • related to https://stackoverflow.com/questions/7862233/twitter-bootstrap-tabs-go-to-specific-tab-on-page-reload – Tim Abell Nov 13 '14 at 17:22

18 Answers18

140

You'll have to use localStorage or cookies to manage that. Here's a quick and dirty solution that can be vastly improved, but may give you a starting point:

$(function() { 
    // for bootstrap 3 use 'shown.bs.tab', for bootstrap 2 use 'shown' in the next line
    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
        // save the latest tab; use cookies if you like 'em better:
        localStorage.setItem('lastTab', $(this).attr('href'));
    });

    // go to the latest tab, if it exists:
    var lastTab = localStorage.getItem('lastTab');
    if (lastTab) {
        $('[href="' + lastTab + '"]').tab('show');
    }
});
Jan
  • 1,231
  • 2
  • 13
  • 19
dgabriel
  • 2,820
  • 1
  • 21
  • 14
  • nice one bud , your solution might be added in joomla 30 core, http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_id=8103&tracker_item_id=29152 – Benn Sep 12 '12 at 16:53
  • 12
    better use `$(this).attr('href')` instead of `$(e.target).attr('id')` which gives you the hash without the complete url. You also have to apply the `.tab()` on the a tag with `data-toggle="tab"` in stead of the `$('#'+lastTab)`. See also: http://stackoverflow.com/questions/16808205/keep-the-current-tab-active-with-twitter-bootstrap-after-a-page-reload/16813902#16813902 – Bass Jobsen May 29 '13 at 12:42
  • This won't work if I have multiple `nav nav-tabs` on the same page, will it? `lastTab` will only contain the last shown tab, independently of the other containers. – Oktav Jun 07 '13 at 10:27
  • @Oktav in that case you can put the id of the container in the key of the localstorage entry and then iterate over localstorage objects when restoring. – DoubleMalt Jun 26 '13 at 14:38
  • 3
    It looks like the method changes slightly in Bootstrap 3. `shown` no longer seems to work, had to change it to `shown.bs.tab`. Note: I understand javascript et al about as well as I understand economics... so someone who knows what's up please feel free to correct me. – Chaz Aug 31 '13 at 23:15
  • 10
    Modified to work with multiple tab controls (and Bootstrap 3): https://gist.github.com/brendanmckenzie/8f8008d3d51c07b2700f – Brendan Nov 23 '14 at 22:47
  • 1
    It is going to the first tab and coming back to the current tab after refresh – Raviteja Dec 01 '15 at 09:30
  • This doesn't work with Safari's private mode because of local storage. – rdupz Mar 13 '16 at 16:29
  • if `//go to the latest tabe, if it exists` part executed faster than `show.bs.tab` event function, it might not work sometime. – user3595632 Dec 14 '16 at 03:28
  • I have a question regarding this one, what if only a certain part of a page is being refreshed? using ````$("#myDiv").load(location.href + " #myDiv");```` ?? – pjustindaryll Sep 21 '19 at 07:40
23

Got this to work using cookies and also removing the 'active' class from any other tabs and tab panes... and adding the 'active' class to the current tab and tab pane.

I'm sure there's a better way to do this, but this appears to work in this case.

Requires the jQuery cookie plugin.

$(function() { 
  $('a[data-toggle="tab"]').on('shown', function(e){
    //save the latest tab using a cookie:
    $.cookie('last_tab', $(e.target).attr('href'));
  });

  //activate latest tab, if it exists:
  var lastTab = $.cookie('last_tab');
  if (lastTab) {
      $('ul.nav-tabs').children().removeClass('active');
      $('a[href='+ lastTab +']').parents('li:first').addClass('active');
      $('div.tab-content').children().removeClass('active');
      $(lastTab).addClass('active');
  }
});
ricsrock
  • 951
  • 9
  • 13
  • I couldn't get the localStorage solution to work even though it seemed logical. This solution out of the box and the $.cookie plugin is VERY handy to have. – Michael J. Calkins Feb 28 '13 at 15:18
  • apply .tab() on the a tag with data-toggle="tab" instead of removing and adding classes see also: http://stackoverflow.com/questions/16808205/keep-the-current-tab-active-with-twitter-bootstrap-after-a-page-reload/16813902#16813902 – Bass Jobsen May 29 '13 at 12:44
  • For my layout, because I was using 'fade in active' for the divs, needed to change last two lines to add or remove 'in active'. – Obromios Feb 17 '16 at 00:13
18

All other answers are correct. This answer will take into account the fact that one might have multiple ul.nav.nav-pills or ul.nav.nav-tabs on the same page. In this case, the previous answers will fail.

Still using localStorage but with a stringified JSON as the value. Here is the code:

$(function() {
  var json, tabsState;
  $('a[data-toggle="pill"], a[data-toggle="tab"]').on('shown', function(e) {
    var href, json, parentId, tabsState;

    tabsState = localStorage.getItem("tabs-state");
    json = JSON.parse(tabsState || "{}");
    parentId = $(e.target).parents("ul.nav.nav-pills, ul.nav.nav-tabs").attr("id");
    href = $(e.target).attr('href');
    json[parentId] = href;

    return localStorage.setItem("tabs-state", JSON.stringify(json));
  });

  tabsState = localStorage.getItem("tabs-state");
  json = JSON.parse(tabsState || "{}");

  $.each(json, function(containerId, href) {
    return $("#" + containerId + " a[href=" + href + "]").tab('show');
  });

  $("ul.nav.nav-pills, ul.nav.nav-tabs").each(function() {
    var $this = $(this);
    if (!json[$this.attr("id")]) {
      return $this.find("a[data-toggle=tab]:first, a[data-toggle=pill]:first").tab("show");
    }
  });
});

This bit can be used on the entire app over all pages and will work for both tabs and pills. Also, make sure the tabs or pills are not active by default, otherwise you will see a flicker effect at page load.

Important: Make sure the parent ul has an id. Thanks Alain

Oktav
  • 2,143
  • 2
  • 20
  • 33
18

For the best option, use this technique:

$(function() { 
  //for bootstrap 3 use 'shown.bs.tab' instead of 'shown' in the next line
  $('a[data-toggle="tab"]').on('click', function (e) {
    //save the latest tab; use cookies if you like 'em better:
    localStorage.setItem('lastTab', $(e.target).attr('href'));
  });

  //go to the latest tab, if it exists:
  var lastTab = localStorage.getItem('lastTab');

  if (lastTab) {
    $('a[href="'+lastTab+'"]').click();
  }
});
nyedidikeke
  • 6,899
  • 7
  • 44
  • 59
Vaimeo
  • 1,078
  • 9
  • 14
12

I prefer storing the selected tab in the hashvalue of the window. This also enables sending links to colleagues, who than see "the same" page. The trick is to change the hash of the location when another tab is selected. If you already use # in your page, possibly the hash tag has to be split. In my app, I use ":" as hash value separator.

<ul class="nav nav-tabs" id="myTab">
    <li class="active"><a href="#home">Home</a></li>
    <li><a href="#profile">Profile</a></li>
    <li><a href="#messages">Messages</a></li>
    <li><a href="#settings">Settings</a></li>
</ul>

<div class="tab-content">
    <div class="tab-pane active" id="home">home</div>
    <div class="tab-pane" id="profile">profile</div>
    <div class="tab-pane" id="messages">messages</div>
    <div class="tab-pane" id="settings">settings</div>
</div>

<script>
    $('#myTab a').click(function (e) {
        e.preventDefault()
        $(this).tab('show')
    });

    // store the currently selected tab in the hash value
    $("ul.nav-tabs > li > a").on("shown.bs.tab", function (e) {
        var id = $(e.target).attr("href").substr(1);
        window.location.hash = id;
    });

    // on load of the page: switch to the currently selected tab
    var hash = window.location.hash;
    $('#myTab a[href="' + hash + '"]').tab('show');
</script>
koppor
  • 19,079
  • 15
  • 119
  • 161
  • Thank you for this answer. It works fine for me and I didn't want to deal with cookies just for this problem so it is great. – nico008 Nov 07 '13 at 13:40
  • @koppor , this does not work there is a postback event. i added the linkbutton `Search `, after clicked on the button, it is the default tab that become active not the current tab. how can i fixed that ?? – Djama Apr 11 '14 at 09:24
6

To prevent the page flashing on the first tab and then the tab that was saved by the cookie (this occurs when you determine the class "active" by default in the first TAB)

Remove the class "active" of tabs and panes like:

<ul class="nav nav-tabs">
<div id="p1" class="tab-pane">

Put the script below to set first tab like default (Requires the jQuery cookie plugin)

    $(function() { 
        $('a[data-toggle="tab"]').on('shown', function(e){
            //save the latest tab using a cookie:
            $.cookie('last_tab', $(e.target).attr('href'));
        });
        //activate latest tab, if it exists:
        var lastTab = $.cookie('last_tab');
        if (lastTab) {
            $('a[href=' + lastTab + ']').tab('show');
        }
        else
        {
            // Set the first tab if cookie do not exist
            $('a[data-toggle="tab"]:first').tab('show');
        }
    });
Jeferson Tenorio
  • 2,030
  • 25
  • 31
4

I had tabs in multiple pages and localStorage keeps lastTab from previous pages as well, so for next page, since it had previous page's lastTab in storage, it didn't find any matching tab here, so nothing was being displayed. I modified it this way.

$(document).ready(function(){
    //console.log($('a[data-toggle="tab"]:first').tab('show'))
    $('a[data-toggle="tab"]').on('shown.bs.tab', function () {
        //save the latest tab; use cookies if you like 'em better:
        localStorage.setItem('lastTab', $(this).attr('href'));
    });

    //go to the latest tab, if it exists:
    var lastTab = localStorage.getItem('lastTab');
    if ($('a[href=' + lastTab + ']').length > 0) {
        $('a[href=' + lastTab + ']').tab('show');
    }
    else
    {
        // Set the first tab if cookie do not exist
        $('a[data-toggle="tab"]:first').tab('show');
    }
})

edit: I've noticed that I'll have to have different lastTab variable names for different pages, otherwise, they'll always overwrite each other. e.g. lastTab_klanten, lastTab_bestellingen etc. for two different pages klanten and bestellingen both having data displayed in tabs.

$(document).ready(function(){
    //console.log($('a[data-toggle="tab"]:first').tab('show'))
    $('a[data-toggle="tab"]').on('shown.bs.tab', function () {
        //save the latest tab; use cookies if you like 'em better:
        localStorage.setItem('lastTab_klanten', $(this).attr('href'));
    });

    //go to the latest tab, if it exists:
    var lastTab_klanten = localStorage.getItem('lastTab_klanten');
    if (lastTab_klanten) {
        $('a[href=' + lastTab_klanten + ']').tab('show');
    }
    else
    {
        // Set the first tab if cookie do not exist
        $('a[data-toggle="tab"]:first').tab('show');
    }
})
GoharSahi
  • 488
  • 1
  • 8
  • 22
3

Want fading effect? Updated version of @Oktav's code:

  1. For Bootstrap 3
  2. Sets up the classes on the li and tab's div to enable fading to work properly. Note that all of the content divs need class="tab-pane fade"

Code:

// See http://stackoverflow.com/a/16984739/64904
// Updated by Larry to setup for fading
$(function() {
  var json, tabsState;
  $('a[data-toggle="pill"], a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
    var href, json, parentId, tabsState;
    tabsState = localStorage.getItem("tabs-state");
    json = JSON.parse(tabsState || "{}");
    parentId = $(e.target).parents("ul.nav.nav-pills, ul.nav.nav-tabs").attr("id");
    href = $(e.target).attr('href');
    json[parentId] = href;
    return localStorage.setItem("tabs-state", JSON.stringify(json));
  });
  tabsState = localStorage.getItem("tabs-state");
  json = JSON.parse(tabsState || "{}");
  $.each(json, function(containerId, href) {
    var a_el = $("#" + containerId + " a[href=" + href + "]");
    $(a_el).parent().addClass("active");
    $(href).addClass("active in");
    return $(a_el).tab('show');
  });
  $("ul.nav.nav-pills, ul.nav.nav-tabs").each(function() {
    var $this = $(this);
    if (!json[$this.attr("id")]) {
      var a_el = $this.find("a[data-toggle=tab]:first, a[data-toggle=pill]:first"),
          href = $(a_el).attr('href');
      $(a_el).parent().addClass("active");
      $(href).addClass("active in");
      return $(a_el).tab("show");
    }
  });
});
Larry K
  • 47,808
  • 15
  • 87
  • 140
3

I made it works with similar solution as @dgabriel, in this case, the links <a> don't need id, it identify the current tab based on the position.

$(function() { 
  $('a[data-toggle="tab"]').on('shown', function (e) {
    var indexTab = $('a[data-toggle="tab"]').index($(this)); // this: current tab anchor
    localStorage.setItem('lastVisitedTabIndex', indexTab);
  });

  //go to the latest tab, if it exists:
  var lastIndexTab  = localStorage.getItem('lastVisitedTabIndex');
  if (lastIndexTab) {
      $('a[data-toggle="tab"]:eq(' + lastIndexTab + ')').tab('show');
  }
});
Jaider
  • 14,268
  • 5
  • 75
  • 82
  • I think your code is wrong way round getItem should be before shown, also soles the issue of declaring indexTab twice. – John Magnolia Oct 21 '14 at 10:26
  • @JohnMagnolia I named the `indexTab` twice but is a diff. index. So I will call the 2nd one `lastIndexTab`. Regarding to `shown`, that is an event, so it won't trigger until you open a tab, so it doesn't matter if is before `getItem`. – Jaider Jan 12 '15 at 14:39
1

I suggest the following changes

  1. Use a plugin like amplify.store which provides a crossbrowser/ crossplatform localstorage API with builtin fallbacks.

  2. Target the tab that needs to be saved like $('#div a[data-toggle="tab"]') so as to extend this functionality to multiple tab containers that exist on the same page.

  3. Use a unique identifier (url ??) to save and restore last used tabs across multiple pages.


$(function() { 
  $('#div a[data-toggle="tab"]').on('shown', function (e) {
    amplify.store(window.location.hostname+'last_used_tab', $(this).attr('href'));
  });

  var lastTab = amplify.store(window.location.hostname+'last_used_tab');
  if (lastTab) {
    $("#div a[href="+ lastTab +"]").tab('show');
  }
});
Sandeep
  • 28,307
  • 3
  • 32
  • 24
1

Simple solution without local storage:

$(".nav-tabs a").on("click", function() {
    location.hash = $(this).attr("href");
});
Francesco Borzi
  • 56,083
  • 47
  • 179
  • 252
0

Server side approach. Be sure all html elements have class="" in case not specified or you will need to handle nulls.

    private void ActiveTab(HtmlGenericControl activeContent, HtmlGenericControl activeTabStrip)
    {
        if (activeContent != null && activeTabStrip != null)
        {
            // Remove active from content
            Content1.Attributes["class"] = Content1.Attributes["class"].Replace("active", "");
            Content2.Attributes["class"] = Content2.Attributes["class"].Replace("active", "");
            Content3.Attributes["class"] = Content3.Attributes["class"].Replace("active", "");

            // Remove active from tab strip
            tabStrip1.Attributes["class"] = tabStrip1.Attributes["class"].Replace("active", "");
            tabStrip2.Attributes["class"] = tabStrip2.Attributes["class"].Replace("active", "");
            tabStrip3.Attributes["class"] = tabStrip3.Attributes["class"].Replace("active", "");

            // Set only active
            activeContent.Attributes["class"] = activeContent.Attributes["class"] + " active";
            activeTabStrip.Attributes["class"] = activeTabStrip.Attributes["class"] + " active";
        }
    }
0

If you want to show the first tab the first time you enter the page use this code:

    <script type="text/javascript">
        function invokeMeMaster() {
        var chkPostBack = '<%= Page.IsPostBack ? "true" : "false" %>';
            if (chkPostBack == 'false') {
                $(function () {
                    // for bootstrap 3 use 'shown.bs.tab', for bootstrap 2 use 'shown' in the next line
                    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
                        // save the latest tab; use cookies if you like 'em better:
                        localStorage.setItem('lastTab', $(this).attr('href'));
                    });

                });
            }
            else {
                $(function () {

                    // for bootstrap 3 use 'shown.bs.tab', for bootstrap 2 use 'shown' in the next line
                    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
                        // save the latest tab; use cookies if you like 'em better:
                        localStorage.setItem('lastTab', $(this).attr('href'));
                    });

                    // go to the latest tab, if it exists:
                    var lastTab = localStorage.getItem('lastTab');
                    if (lastTab) {
                        $('[href="' + lastTab + '"]').tab('show');
                    }

                });

            }
        }
        window.onload = function() { invokeMeMaster(); };

    </script>
ruben
  • 109
  • 2
  • 10
0

Here is a snippet I made that works with Bootstrap 3 and jQuery and with different URLs containing different tabs. It does not support multiple tabs per page though but it should be an easy modification if you need that feature.

/**
 * Handles 'Bootstrap' package.
 *
 * @namespace bootstrap_
 */

/**
 * @var {String}
 */
var bootstrap_uri_to_tab_key = 'bootstrap_uri_to_tab';

/**
 * @return {String}
 */
function bootstrap_get_uri()
{
    return window.location.href;
}

/**
 * @return {Object}
 */
function bootstrap_load_tab_data()
{
    var uriToTab = localStorage.getItem(bootstrap_uri_to_tab_key);
    if (uriToTab) {
    try {
        uriToTab = JSON.parse(uriToTab);
        if (typeof uriToTab != 'object') {
        uriToTab = {};
        }
    } catch (err) {
        uriToTab = {};
    }
    } else {
    uriToTab = {};
    }
    return uriToTab;
}

/**
 * @param {Object} data
 */
function bootstrap_save_tab_data(data)
{
    localStorage.setItem(bootstrap_uri_to_tab_key, JSON.stringify(data));
}

/**
 * @param {String} href
 */
function bootstrap_save_tab(href)
{
    var uri = bootstrap_get_uri();
    var uriToTab = bootstrap_load_tab_data();
    uriToTab[uri] = href;
    bootstrap_save_tab_data(uriToTab);
}

/**
 *
 */
function bootstrap_restore_tab()
{
    var uri = bootstrap_get_uri();
    var uriToTab = bootstrap_load_tab_data();
    if (uriToTab.hasOwnProperty(uri) &&
    $('[href="' + uriToTab[uri] + '"]').length) {
    } else {
    uriToTab[uri] = $('a[data-toggle="tab"]:first').attr('href');
    }
    if (uriToTab[uri]) {
        $('[href="' + uriToTab[uri] + '"]').tab('show');
    }
}

$(document).ready(function() {

    if ($('.nav-tabs').length) {

    // for bootstrap 3 use 'shown.bs.tab', for bootstrap 2 use 'shown' in the next line
    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
        bootstrap_save_tab($(this).attr('href'));
    });
    bootstrap_restore_tab();

    }

});
cjohansson
  • 1,058
  • 10
  • 13
0

$(document).ready(function () {

        if (JSON.parse(localStorage.getItem('currentClass')) == "active")
        {
            jQuery('#supporttbl').addClass('active')
            $('.sub-menu').css({ "display": "block" });
        }

        $("#supporttbl").click(function () { 
            var currentClass;
            if ($(this).attr('class')== "active") { 

                currentClass = $(this).attr('class');

                localStorage.setItem('currentClass', JSON.stringify(currentClass));
                console.log(JSON.parse(localStorage.getItem('currentClass')));

                jQuery('#supporttbl').addClass('active')
                $('.sub-menu').css({ "display": "block" });

            } else {

                currentClass = "Null"; 

                localStorage.setItem('currentClass', JSON.stringify(currentClass));
                console.log(JSON.parse(localStorage.getItem('currentClass')));

                jQuery('#supporttbl').removeClass('active')
                $('.sub-menu').css({ "display": "none" });

            }  
        });

});

0

if you have more than one tab in the page, you can use the following code

<script type="text/javascript">
$(document).ready(function(){
    $('#profileTabs').on('show.bs.tab', function(e) {
        localStorage.setItem('profileactiveTab', $(e.target).attr('href'));
    });
    var profileactiveTab = localStorage.getItem('profileactiveTab');
    if(profileactiveTab){
        $('#profileTabs a[href="' + profileactiveTab + '"]').tab('show');        
    }
    $('#charts-tab').on('show.bs.tab', function(e) {
        localStorage.setItem('chartsactiveTab', $(e.target).attr('href'));
    });
    var chartsactiveTab = localStorage.getItem('chartsactiveTab');
    if(chartsactiveTab){
        $('#charts-tab a[href="' + chartsactiveTab + '"]').tab('show');        
    }     
});
</script>
Mohamed Sami
  • 866
  • 10
  • 22
0

This will refresh the tabs but only after everything in the controller is loaded.

// >= angular 1.6 angular.element(function () {
angular.element(document).ready(function () {
    //Here your view content is fully loaded !!
    $('li[href="' + location.hash + '"] a').tab('show');
});
PHPGuru
  • 398
  • 3
  • 9
0

I'm using this with MVC:

  • There is a SelectedTab integer field in the model to send the value to the POST method

JavaScript Section:

<script type="text/javascript">
    $(document).ready(function () {
       var index = $("input#SelectedTab").val();
       $("#tabstrip > ul li:eq(" + index + ")").addClass("k-state-active");

       $("#tabstrip").kendoTabStrip();
    });
    function setTab(index) {
      $("input#SelectedTab").val(index)
    }
</script>

HTML Section:

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.SelectedTab)
<div id="tabstrip">
    <ul>
        <li onclick="setTab(0)">Content 0</li>
        <li onclick="setTab(1)">Content 1</li>
        <li onclick="setTab(2)">Content 2</li>
        <li onclick="setTab(3)">Content 3</li>
        <li onclick="setTab(4)">Content 4</li>
    </ul>
    <div>

    </div>
    <div>

    </div>
    <div>

    </div>
    <div>

    </div>
    <div>

    </div>
</div>
<div class="content">
    <button type="submit" name="save" class="btn bg-blue">Save</button>
</div>
}
Carlos Toledo
  • 2,519
  • 23
  • 23