Twitter Bootstrap - Tabs - URL doesn't change

JqueryTwitter Bootstrap

Jquery Problem Overview


I'm using Twitter Bootstrap and its "tabs".

I have the following code:

<ul class="nav nav-tabs">
    <li class="active"><a data-toggle="tab" href="#add">add</a></li>
    <li><a data-toggle="tab" href="#edit" >edit</a></li>
    <li><a data-toggle="tab" href="#delete" >delete</a></li>
</ul>

The tabs work properly, but the in the URL is not added the #add, #edit, #delete.

When I remove data-toggle the URL changes, but the tabs don't work.

Any solutions for this?

Jquery Solutions


Solution 1 - Jquery

Try this code. It adds tab href to url + opens tab based on hash on page load:

$(function(){
  var hash = window.location.hash;
  hash && $('ul.nav a[href="' + hash + '"]').tab('show');

  $('.nav-tabs a').click(function (e) {
    $(this).tab('show');
    var scrollmem = $('body').scrollTop() || $('html').scrollTop();
    window.location.hash = this.hash;
    $('html,body').scrollTop(scrollmem);
  });
});

Solution 2 - Jquery

There are three components necessary for a complete solution:

  1. Show the correct tab when the page is loaded if there is a hash in the URL.
  2. Changing the hash in the URL when the tab is changed.
  3. Change the tab when the hash changes in the URL (back / forward buttons), and make sure the first tab is cycled correctly.

I don't think any of the comments here, nor the accepted answer, handle all of these scenarios.

As there's quite a bit involved, I think it's neatest as a small jQuery plugin: https://github.com/aidanlister/jquery-stickytabs

You can call the plugin like so:

$('.nav-tabs').stickyTabs();

I've made a blog post for this, http://aidanlister.com/2014/03/persisting-the-tab-state-in-bootstrap/

Solution 3 - Jquery

Using data-toggle="tab" asks the plugin to handle the tabs, which while doing it calls preventDefault on the event (code on github).

You can use your own tab activation, and let the event go through :

$('.nav-tabs a').click(function (e) {
    // No e.preventDefault() here
    $(this).tab('show');
});

And you must remove the attribute data-toggle="tab"

Check the doc if you have doubts.

Solution 4 - Jquery

As your anchor elements already change the url hash, listening to onhashchange event is another good option. As @flori already mentioned, this method works nice with the browser back button.

var tabs$ = $(".nav-tabs a");

$( window ).on("hashchange", function() {
    var hash = window.location.hash, // get current hash
        menu_item$ = tabs$.filter('[href="' + hash + '"]'); // get the menu element

    menu_item$.tab("show"); // call bootstrap to show the tab
}).trigger("hashchange");

Finally, triggering the event just after you define the listener will also help showing the right tab on page load.

Solution 5 - Jquery

My solution to your problem:

First add new data-value attribute to each a link, like this:

<ul class="nav nav-tabs">
    <li class="active">
        <a data-toggle="tab" href="#tab-add" data-value="#add">add</a>
    </li>
    <li>
        <a data-toggle="tab" href="#tab-edit" data-value="#edit">edit</a>
    </li>
    <li>
        <a data-toggle="tab" href="#tab-delete" data-value="#delete">delete</a>
    </li>
</ul>

Second, change ids of tabs, e.g. from add to tab-add , also update hrefs to include tab- prefix:

<div class="tab-content">
    <div class="tab-pane" id="tab-add">Add panel</div>
    <div class="tab-pane" id="tab-edit">Edit panel</div>
    <div class="tab-pane" id="tab-delete">Panel panel</div>
</div>

And finally js code:

<script type="text/javascript">
    $(function () {
        var navTabs = $('.nav-tabs a');
        var hash = window.location.hash;
        hash && navTabs.filter('[data-value="' + hash + '"]').tab('show');

        navTabs.on('shown', function (e) {
            var newhash = $(e.target).attr('data-value');
            window.location.hash = newhash;
        });
    })
</script>

Here is jsFiddle - but it does not work because of iframe used by jsFiddle, but you can read source of my solution.

Solution 6 - Jquery

Same problem with CakePHP with Bootstrap 3 Tabs, plus when i send with external URL and anchor, it jumps to the section losing my menu, after review many solutions made this...

thanks to: http://ck.kennt-wayne.de/2012/dec/twitter-bootstrap-how-to-fix-tabs

$(document).ready(function()
 {	
//Redirecciona al tab, usando un prefijo al cargar por primera vez, al usar redirect en cake #_Pagos	
//Redirecciona al tab, usando #Pagos
/* Automagically jump on good tab based on anchor; for page reloads or links */
 if(location.hash) 
  {
     $('a[href=' + location.hash + ']').tab('show');		 
  }


//Para evitar el bajar al nivel del tab, (al mostrarse el tab subimos)
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) 
{
	location.hash = $(e.target).attr('href').substr(1);
	scrollTo(0,0);		
});



//Actualiza el URL con el anchor o ancla del tab al darle clic
 /* Update hash based on tab, basically restores browser default behavior to
 fix bootstrap tabs */
$(document.body).on("click", "a[data-toggle]", function(event) 
  {
	location.hash = this.getAttribute("href");
  });

  
//Redirecciona al tab, al usar los botones de regresar y avanzar del navegador.
/* on history back activate the tab of the location hash if exists or the default tab if no hash exists */   
$(window).on('popstate', function() 
{
  //Si se accesa al menu, se regresa al tab del perfil (activo default), fixed conflict with menu
  //var anchor = location.hash || $("a[data-toggle=tab]").first().attr("href");
  var anchor = location.hash;
  $('a[href=' + anchor + ']').tab('show');

});	  

});//Fin OnReady

 

Solution 7 - Jquery

There is also a simple way to react on hash changes (e.g. back button). Simply add an hashchange event listener to tomaszbak solution:

$(function(){
  // Change tab on load
  var hash = window.location.hash;
  hash && $('ul.nav a[href="' + hash + '"]').tab('show');

  $('.nav-tabs a').click(function (e) {
    $(this).tab('show');
    var scrollmem = $('body').scrollTop();
    window.location.hash = this.hash;
    $('html,body').scrollTop(scrollmem);
  });

  // Change tab on hashchange
  window.addEventListener('hashchange', function() {
    var changedHash = window.location.hash;
    changedHash && $('ul.nav a[href="' + changedHash + '"]').tab('show');
  }, false);
});

Solution 8 - Jquery

I understood that OP said using JQuery but you can simply use vanilla JS to do that:

document.querySelectorAll('ul.nav a.nav-link').forEach(link => {
    link.onclick = () => window.history.pushState(null, null, link.attributes.href.value);
});

Solution 9 - Jquery

Most simple, assuming you're using the documented data-toggle="tab" syntax described here:

$(document).on('shown.bs.tab', function(event) {
  window.location.hash = $(event.target).attr('href');
});

Solution 10 - Jquery

I am using Bootstrap 3.3.* and none of the above solution helped me, even marked as answer one. I just added below script and worked.

$(function(){
    var hash = document.location.hash;
    if (hash) {
       $('.navbar-nav a[href="' + hash + '"]').tab('show');
    }
    $('a[data-toggle="tab"]').on('click', function (e) {
       history.pushState(null, null, $(this).attr('href'));
    });
});

Hope this helps you.

Solution 11 - Jquery

For those using Ruby on Rails or any other server side script, you will want to use the anchor option on paths. This is because once the page loads, it does not have the URL hash available. You will want to supply the correct tab via your link or form submission.

<%= form_for @foo, url: foo_path(@foo, anchor: dom_id(foo)) do |f| %>
# Or
<%= link_to 'Foo', foo_path(@foo, anchor: dom_id(foo)) %>

If you are using a prefix to prevent the window from jumping to the id:

<%= form_for @foo, url: foo_path(@foo, anchor: "bar_#{dom_id(foo)}") do |f| %>

Then you CoffeeScript:

  hash = document.location.hash
  prefix = 'bar_'
  $('.nav-tabs a[href=' + hash.replace(prefix, '') + ']').tab 'show' if hash
  $('.nav-tabs a').on 'shown.bs.tab', (e) ->
    window.location.hash = e.target.hash.replace '#', '#' + prefix

Or JavaScript:

var hash, prefix;

hash = document.location.hash;
prefix = 'bar_';

if (hash) {
  $('.nav-tabs a[href=' + hash.replace(prefix, '') + ']').tab('show');
}

$('.nav-tabs a').on('shown.bs.tab', function(e) {
  window.location.hash = e.target.hash.replace('#', '#' + prefix);
});

This should work in Bootstrap 3.

Solution 12 - Jquery

Thanks to @tomaszbak for the original solution however since my edits got rejected and I'm unable to comment on his post yet I will leave my slightly improved and more readable version here.

It does basically the same thing but if fixes the cross browser compatibility issue I had with his.

$(document).ready(function(){
   // go to hash on window load
   var hash = window.location.hash;
   if (hash) {
       $('ul.nav a[href="' + hash + '"]').tab('show');
   }
   // change hash on click
   $('.nav-tabs a').click(function (e) {
       $(this).tab('show');
       if($('html').scrollTop()){
           var scrollmem = $('html').scrollTop(); // get scrollbar position (firefox)
       }else{
           var scrollmem = $('body').scrollTop(); // get scrollbar position (chrome)
       }
       window.location.hash = this.hash;
       $('html,body').scrollTop(scrollmem); // set scrollbar position
   });
});

Solution 13 - Jquery

Here's an option using history.pushState so that you can use your browser history to go back to a previous tab

  $(document).ready(function() {
  // add a hash to the URL when the user clicks on a tab
  $('a[data-toggle="tab"]').on('click', function(e) {
    history.pushState(null, null, $(this).attr('href'));
  });
  // navigate to a tab when the history changes
  window.addEventListener("popstate", function(e) {
    var activeTab = $('[href=' + location.hash + ']');
    if (activeTab.length) {
      activeTab.tab('show');
    } else {
      $('.nav-tabs a:first').tab('show');
    }
  });
});

Solution 14 - Jquery

None of the above worked for me, so here's my how I got mine working:

  1. Add class="tab-link" to all links needing this functionality

  2. Add the following code to your javascript:

    window.addEventListener
    (
    'popstate',
    function( event )
    {
    tab_change();
    }
    );

    function tab_change() { var hash = window.location.hash; hash && $( 'ul.nav a[href="' + hash + '"]' ).tab( 'show' );

     $( '.tab-link' ).click
     (
         function( e )
         {
             $( this ).tab( 'show' );
    
             var scrollmem = $( 'body' ).scrollTop() || $( 'html' ).scrollTop();
             window.location.hash = this.hash;
             $( 'html,body' ).scrollTop( scrollmem );
    
             $( 'ul.nav-tabs a[href="' + window.location.hash + '"]' ).tab( 'show' );
         }
     );
    

    }

Solution 15 - Jquery

This also fixes an extremely obscure tab a href not firing when using jquery and bootstrap

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> 

<script type="text/javascript">
$('.nav-tabs a').click(function (e) {
    // No e.preventDefault() here.
    $(this).tab('show');
});
</script>

<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIvanka TodorovaView Question on Stackoverflow
Solution 1 - JquerytomaszbakView Answer on Stackoverflow
Solution 2 - JqueryAidanView Answer on Stackoverflow
Solution 3 - JquerySherbrowView Answer on Stackoverflow
Solution 4 - JqueryhalilbView Answer on Stackoverflow
Solution 5 - JquerypsulekView Answer on Stackoverflow
Solution 6 - JqueryHenry Gabriel González MontejoView Answer on Stackoverflow
Solution 7 - JqueryFloriView Answer on Stackoverflow
Solution 8 - Jqueryalexandre-rousseauView Answer on Stackoverflow
Solution 9 - JqueryFredView Answer on Stackoverflow
Solution 10 - JqueryAbhimanyuView Answer on Stackoverflow
Solution 11 - JqueryMohamadView Answer on Stackoverflow
Solution 12 - JqueryFuxyView Answer on Stackoverflow
Solution 13 - JqueryAdam HeyView Answer on Stackoverflow
Solution 14 - JquerysimonlView Answer on Stackoverflow
Solution 15 - JqueryRayView Answer on Stackoverflow