New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

activate tab based on url hash #581

Closed
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
@theill
Copy link

theill commented Nov 7, 2011

selects a tab if a hash is available in url and hash matches one of the tab names

@dorgan

This comment has been minimized.

Copy link

dorgan commented Nov 7, 2011

The only addition other addition that would need to be made is the default action of clicking the link would need to happen so that the changing of a tab adds a hash to the URL

@fat

This comment has been minimized.

Copy link
Member

fat commented Nov 7, 2011

Don't want to add this - i went down this road once and it's really hard to provide consistent behavior down to ie7. Also, like @dorgan said I think we would need to get it working with urls all together

@fat fat closed this Nov 7, 2011

@dorgan

This comment has been minimized.

Copy link

dorgan commented Nov 7, 2011

I implemented this with a cookies and the change event. I will post the code later. Then your serverside can determine whether or not to add the active class or not.

@theill

This comment has been minimized.

Copy link

theill commented Nov 7, 2011

ok. @dorgan I would love to see that code, thanks.

@dorgan

This comment has been minimized.

Copy link

dorgan commented Nov 7, 2011

#mainnav is the ul element of the tabbar

$('#mainnav').tabs().bind('change', function (e) {
    var parts = decodeURI(e.target).split('#');
    $.cookie('cur_tab',parts['1']);
});

I am using a jquery cookie plugin for this BTW.

@pokonski pokonski referenced this pull request Nov 27, 2011

Closed

Tabs and hashtag #700

@dannyvankooten

This comment has been minimized.

Copy link

dannyvankooten commented Jan 5, 2012

Just to be clear, @fat what exactly is the problem regarding inconsistency down to IE7?

I was looking for this behaviour and ended up here. Changed bootstrap-tabs.js a little and things seem to work fine in all browsers listed on Bootstrap's main page. Here is the code I used.

In bootstrap-tabs.js I added a line to add the hash to the URL. The slash is there to prevent jumping to the mentioned element.

if ( /^#\w+/.test(href) ) {
    e.preventDefault()
    window.location.hash = '/' + href.substr(1);
    ...

Then, on pages that implemented tabs all I had to do was check the hash and trigger a click on the link element with the corresponding hash, if it exists..

if (window.location.hash) {
    $(".tabs li a[href='#" + window.location.hash.substr(2) + "']").click()
 }

I'm probably overlooking something and as I'm pretty curious, what is it? ;)

PS. You'll find a live, testable example here.

@fat

This comment has been minimized.

Copy link
Member

fat commented Jan 5, 2012

This is just an incomplete implementation is all. Really if you were going to support this - you should support full navigation (with history, clicking the back and forward buttons, etc.) That requires listening to hash change events and it get's pretty rough.

@davidbgk

This comment has been minimized.

Copy link

davidbgk commented Feb 16, 2012

I got this use-case too: 3 forms in 3 different tabs, I want to be able to display the right tab on user submission if there are errors on the filled form. If I remember correctly the tabs plugin from jQuery UI is doing that.

Is it an option to do not support that feature for IE 7?

@tboyko

This comment has been minimized.

Copy link

tboyko commented Feb 23, 2012

I too wanted to be able to return to a specific tab on page load, particularly for server-side form validation purposes. It seems to me that the particular tab to have selected should be a component of the URL, so I execute the following javascript on page load. It checks for an anchor and highlights the relevant tab. Otherwise, it highlights the first tab.

if (window.location.hash.length > 0) {
    $('ul.nav-tabs > li > a[href="' + window.location.hash + '"]').tab('show');
} else {
    $('ul.nav-tabs > li > a:first').tab('show');
}
@Geczy

This comment has been minimized.

Copy link

Geczy commented Feb 27, 2012

Same here as @davidbgk

@dsully

This comment has been minimized.

Copy link

dsully commented Feb 29, 2012

I'm using the excellent History.js for this functionality with tabs. Allowing the browser's forward & back buttons to work properly.

Should all be cross-browser compatible, with the possible exception of the window.location.hash = '';

This code doesn't actually update the URL hash at all, but instead uses pushState().

Though if the user has a hash initially, it will be read and the correct tab is shown.

Don't set a 'active' tab in the HTML itself, but do so in the JS. Alternatively, you could check for a different class, etc.

No modification of Bootstrap itself required.

$(document).ready(function() {

    // Handle tabs, page reloads & browser forward/back history.
    var History = window.History;

    if (!History.enabled) {
      return false;
    }

    $(window).bind('load statechange', function () {
      var State = History.getState();
      var hash  = History.getHash();

      // Our default tab.
      if (!State.data || !State.data.tab) {
        if (hash) {
          State.data.tab = hash;
          window.location.hash = '';
        } else {
          State.data.tab = 'YOUR DEFAULT ACTIVE TAB NAME';
        }
      }

      $('ul.nav-tabs > li > a[href="#' + State.data.tab + '"]').tab('show');
    });

    $('a[data-toggle="tab"]').on('shown', function (event) {

      // Set the selected tab to be the current state. But don't update the URL.
      var url = event.target.href.split("#")[0];
      var tab = event.target.href.split("#")[1];

      var State = History.getState();

      // Don't set the state if we haven't changed tabs.
      if (State.data.tab != tab) {
        History.pushState({'tab': tab}, null, url);
      }
    });
  });
@Geczy

This comment has been minimized.

Copy link

Geczy commented Mar 2, 2012

I couldn't get the above code by @dsully to work by default. I had to remove that last if statement with the pushState and then everything works awesome.

Now what if we have nav tabs on different pages? For example, 5 tabs on page 1, and 4 tabs on page 2. When you visit a tab on page 1, it will get lost after visiting a tab on page 2.

@dsully

This comment has been minimized.

Copy link

dsully commented Mar 2, 2012

Ah, yes - there's a slight bug there. It should be:

if (State.data.tab != tab) { ...

You'll need to update the url as appropriate for your business logic if you have tabs split across pages.

@Geczy

This comment has been minimized.

Copy link

Geczy commented Mar 2, 2012

Alright last note, what about having the fade class on tabs? Removing the active class takes away the fade effect as well when switching between tabs. So the history is snappy rather than smooth when using the above code :(

@Geczy

This comment has been minimized.

Copy link

Geczy commented Mar 2, 2012

Your script works out of the box for multiple pages with tabs, neat !

@Geczy

This comment has been minimized.

Copy link

Geczy commented Mar 2, 2012

Ah here's a bug then (or maybe just a feature request?)

Dropdown tabs are not stored, likely just due to this bit:

 $('ul.nav-tabs > li > a[href="#' + State.data.tab + '"]').tab('show');
@dsully

This comment has been minimized.

Copy link

dsully commented Mar 2, 2012

You'll need to adjust for whatever your business logic is. My code is meant as an example of what one can do - and should work for the basic nav/pill tabs.

FYI, Gist of the code here: https://gist.github.com/1938283

@chayner

This comment has been minimized.

Copy link

chayner commented Mar 29, 2012

I went a slightly different route, and used Ben Alman's hashchange plugin instead.

// Function to activate the tab
function activateTab () {
   var activeTab = $('[href=' + location.hash + ']');
   activeTab && activeTab.tab('show');      
}

// Trigger when the page loads
activateTab();

// Trigger when the hash changes (forward / back)
$(window).hashchange(function(e) {
    activateTab();
});

// Change hash when a tab changes
$('a[data-toggle="tab"], a[data-toggle="pill"]').on('shown', function (event) {
    location.href = event.target.href;
});

@alvioshki

This comment has been minimized.

Copy link

alvioshki commented Apr 4, 2012

I use @chayner way - it works fine, but I have added a small change. The script is changing the hash value to the id of the tab pane therefore I have experienced page jumping to the middle when loading. So I am adding / removing a prefix to the id (a slash sign) in order to avoid that - the page loads at the top now.

function activateTab() {
    var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
    activeTab && activeTab.tab('show');
}

$('a[data-toggle="tab"], a[data-toggle="pill"]').on('shown', function () {
    window.location.hash = '/' + $(this).attr('href').replace('#', '');
});
@jiji262

This comment has been minimized.

Copy link

jiji262 commented Apr 5, 2012

@chayner 's way works fine, but the contents will scroll to the element when clicking on one tab due to the url contains #file_upload.
And fortunately this problem by @alvioshkand he changed the hash to i#/file_upload format. That's great!

The full scripts you need to add are :

$(function(){
    // Function to activate the tab
    function activateTab() {
        var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
        activeTab && activeTab.tab('show');
    }

    // Trigger when the page loads
    activateTab();

    // Trigger when the hash changes (forward / back)
    $(window).hashchange(function(e) {
        activateTab();
    });

    // Change hash when a tab changes
    $('a[data-toggle="tab"], a[data-toggle="pill"]').on('shown', function () {
        window.location.hash = '/' + $(this).attr('href').replace('#', '');
    }); 
});

BTW, remember to include Ben Alman's hashchange plugin.
http://benalman.com/projects/jquery-hashchange-plugin/

@ftcmnc

This comment has been minimized.

Copy link

ftcmnc commented Aug 16, 2012

@adibreaban

This comment has been minimized.

Copy link

adibreaban commented Dec 19, 2012

How about nested tabs? Will @jiji262 's solution still work? I managed to get the nested tabs working just by removing the > first-child selector from

.tab-content > .tab-pane {
    display: none;
}
.tab-content > .active {
    display: block;
}
@ghost

This comment has been minimized.

Copy link

ghost commented Dec 30, 2012

@raulferras

This comment has been minimized.

Copy link

raulferras commented May 7, 2013

I've been using @jiji262 and works like a charm, but I had to modify it so it works with tabs added dinamically:

$(function(){
    // Function to activate the tab
    function activateTab() {
        var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
        activeTab && activeTab.tab('show');
    }

    // Trigger when the page loads
    activateTab();

    // Trigger when the hash changes (forward / back)
    $(window).hashchange(function(e) {
        activateTab();
    });

    // Change hash when a tab changes
    // Handle shown event using delegation 
    $(document).on('shown.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function () {
        window.location.hash = '/' + $(this).attr('href').replace('#', '');
    }); 
});
@mrfosip

This comment has been minimized.

Copy link

mrfosip commented Jun 17, 2013

Thanks for this guys!
I changed it a bit to not need the hashchange plugin:

$(function(){
  // Function to activate the tab
  function activateTab() {
      var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
      activeTab && activeTab.tab('show');
  }

  // Trigger when the page loads
  activateTab();

  // Trigger when the hash changes (forward / back)
  $(window).on('hashchange', function() {
      activateTab();
  });

  // Change hash when a tab changes
  // Handle shown event using delegation 
  $(document).on('shown.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function () {
      window.location.hash = $(this).attr('href').replace('#', '');
  }); 
});
@heruan

This comment has been minimized.

Copy link

heruan commented Sep 18, 2013

Now that BS 3 dropped IE 7 support, will automatic tab activation based on hash change be supported?

@cvrebert

This comment has been minimized.

Copy link
Member

cvrebert commented Sep 18, 2013

It's not on the roadmap at this point.

@cvrebert

This comment has been minimized.

Copy link
Member

cvrebert commented Dec 11, 2013

X-Ref: #2415

@angelo2231

This comment has been minimized.

Copy link

angelo2231 commented Sep 14, 2015

I just want to ask how to load the ajax content on this script because on ordinary tab content it shows but in the ajax content is not working hoping somebody can answer me I'm a first timer in bootstrap

@ghost ghost referenced this pull request May 21, 2016

Closed

Panes should change the URL #218

@oranges13

This comment has been minimized.

Copy link

oranges13 commented Aug 2, 2017

The solution from @mrfosip worked for me, but due to updates in the javascript for bootstrap, I had to modify the script as follows:

$(function(){
	// Function to activate the tab
	function activateTab() {
		var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
		activeTab && activeTab.tab('show');
	}

	// Trigger when the page loads
	activateTab();

	// Trigger when the hash changes (forward / back)
	$(window).on('hashchange', function() {
		activateTab();
	});

	// Change hash when a tab changes
	// Handle shown event using delegation

        // Changed 'shown.tab.data-api' to 'shown.bs.tab' 
	$(document).on('shown.bs.tab', '[data-toggle="tab"], [data-toggle="pill"]', function () {
		window.location.hash = $(this).attr('href').replace('#', '');
	});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment