87
votes

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>
18
This seems to be a duplicate question to stackoverflow.com/questions/18999501/…koppor

18 Answers

139
votes

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');
    }
});
23
votes

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');
  }
});
18
votes

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

18
votes

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();
  }
});
12
votes

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>
6
votes

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');
        }
    });
4
votes

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');
    }
})
3
votes

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");
    }
  });
});
3
votes

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');
  }
});
1
votes

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');
  }
});
1
votes

Simple solution without local storage:

$(".nav-tabs a").on("click", function() {
    location.hash = $(this).attr("href");
});
0
votes

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
votes

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>
0
votes

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();

    }

});
0
votes

$(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
votes

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>
0
votes

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');
});
0
votes

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>
}