327

I spent an unrealistic amount of time trying to fire a function when the tab changes of the bootstrap 3 tab/navbar and literally all suggestions google spat out were wrong/did not work.

How to go about this?

Meta-edit: see comment

Gerben Rampaart
  • 9,853
  • 3
  • 26
  • 32
  • 4
    This was really useful! If we want to watch out only for a specific tab we can watch for $("a[href='#tab_name']").on('shown.bs.tab', fn) Of course we can specify further selectors if a[href='#tab_name'] isn't guaranteed to be unique. – msanjay Oct 01 '14 at 14:32
  • Possible duplicate of [Twitter Bootstrap - Perform action on tab "shown" event](http://stackoverflow.com/questions/13164239/twitter-bootstrap-perform-action-on-tab-shown-event) – rogerdpack Apr 24 '17 at 13:57
  • @rogerdpack 'http://stackoverflow.com/questions/13164239/twitter-bootstrap-perform-action-on-tab-shown-event' seems confusing to redirect to, it's questioner took a wrong path and looked for an answer within it's scope, the question is overly long and specific and the accepted answer seems to reflect that because it is certainly not the valid answer to my question. The fact this question did not help as many people probably is related to that. – Gerben Rampaart Apr 24 '17 at 14:59

8 Answers8

507

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
  var target = $(e.target).attr("href") // activated tab
  alert(target);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>

<ul id="myTab" class="nav nav-tabs">
  <li class="active"><a href="#home" data-toggle="tab">Home</a></li>
  <li class=""><a href="#profile" data-toggle="tab">Profile</a></li>
</ul>
<div id="myTabContent" class="tab-content">
  <div class="tab-pane fade active in" id="home">
    home tab!
  </div>
  <div class="tab-pane fade" id="profile">
    profile tab!
  </div>
</div>
Gerben Rampaart
  • 9,853
  • 3
  • 26
  • 32
  • 1
    Thanks a lot, spent quite some time on this before finding your answer, you rock! – Hajjat Oct 13 '15 at 05:42
  • 3
    If you have to use the change event (regardless of the action from the link), simply use`$(document).on('shown.bs.tab', function (e) { console.log('ae'); });` – Aline Matos May 13 '16 at 13:02
  • 1
    Perfect, saved me a lot of time with this! – Justin Aug 12 '16 at 18:20
  • I have a small doubt in this. I declared the `target` as a global variable and assigned the value as mentioned above. When I first load the page, I get the value(alert) of target as undefined. But, when I change the tab and assign that value to the target, I'm not getting any alert. Not even an error message. What should I do, in order to bring it outside that loop? I've declared the variable outside the document.ready function. – SSS Nov 02 '16 at 12:31
  • This works only if I click on another tab. How to add that trigger for default tab? I need to load ajax on every tab. But with this it loads only when I click another tab and then the first again. – Kārlis Janisels Nov 03 '16 at 12:31
  • [Official documentation](http://getbootstrap.com/javascript/#tabs-events) is probably more handy. – T30 Apr 12 '17 at 16:35
  • $('a[data-toggle="pill"]').on('shown.bs.pill', function (e) { }); I want this to work for nav-pills. Will this work? – monisha May 05 '17 at 12:16
  • Why tab event should be handled on tab link??? What is we don't have tab navigations in code?.. – Viktor Kruglikov Sep 13 '17 at 13:35
  • instead of reading attribute if href, use this to read a selected hash instead var hash = e.currentTarget.hash; – st35ly Mar 13 '18 at 22:55
  • This didn't work for me. The solution that worked for me was from this answer: https://stackoverflow.com/questions/23211543/tab-shown-event-not-firing-twitter-bootstrap$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) { alert('TAB CHANGED'); }) – DavidHyogo May 02 '18 at 06:59
  • Superb! You make my day! – ɐsɹǝʌ ǝɔıʌ Mar 09 '20 at 11:52
96
$(function () {
    $('#myTab a:last').tab('show');
});

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    var target = $(e.target).attr("href");
    if ((target == '#messages')) {
        alert('ok');
    } else {
        alert('not ok');
    }
});

the problem is that attr('href') is never empty.

Or to compare the #id = "#some value" and then call the ajax.

Majid Fouladpour
  • 29,356
  • 21
  • 76
  • 127
Florin
  • 5,781
  • 2
  • 20
  • 30
41

Thanks to @Gerben's post came to know there are two events show.bs.tab (before the tab is shown) and shown.bs.tab (after the tab is shown) as explained in the docs - Bootstrap Tab usage

An additional solution if we're only interested in a specific tab, and maybe add separate functions without having to add an if - else block in one function, is to use the a href selector (maybe along with additional selectors if required)

 $("a[href='#tab_target_id']").on('shown.bs.tab', function(e) {
      console.log('shown - after the tab has been shown');
 });

 // or even this one if we want the earlier event
 $("a[href='#tab_target_id']").on('show.bs.tab', function(e) {
      console.log('show - before the new tab has been shown');
 });

demo

msanjay
  • 2,255
  • 2
  • 19
  • 19
  • Great solution, I need to catch after tab show event and call to my angular function, this solution saved me couple of hours! – Allen Nov 04 '15 at 10:19
13

To add to Mosh Feu answer, if the tabs where created on the fly like in my case, you would use the following code

$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
    var tab = $(e.target);
    var contentId = tab.attr("href");

    //This check if the tab is active
    if (tab.parent().hasClass('active')) {
         console.log('the tab with the content id ' + contentId + ' is visible');
    } else {
         console.log('the tab with the content id ' + contentId + ' is NOT visible');
    }

});

I hope this helps someone

Jaylen
  • 39,043
  • 40
  • 128
  • 221
8

This worked for me.

$('.nav-pills > li > a').click( function() {
    $('.nav-pills > li.active').removeClass('active');
    $(this).parent().addClass('active');
} );
2

I use another approach.

Just try to find all a where id starts from some substring.

JS

$('a[id^=v-photos-tab]').click(function () {
     alert("Handler for .click() called.");
});

HTML

<a class="nav-item nav-link active show"  id="v-photos-tab-3a623245-7dc7-4a22-90d0-62705ad0c62b" data-toggle="pill" href="#v-photos-3a623245-7dc7-4a22-90d0-62705ad0c62b" role="tab" aria-controls="v-requestbase-photos" aria-selected="true"><span>Cool photos</span></a>
NoWar
  • 36,338
  • 80
  • 323
  • 498
1

A similar answer to Gerben Rampaart for bootstrap 5 tabs. Just a few differences with the current tabs HTML in the documentation:

$('button[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
  var target = $(e.target).data("bs-target") // activated tab
  alert(target);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"/>

<nav>
  <div class="nav nav-tabs" id="nav-tab" role="tablist">
<button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>
<button class="nav-link" id="nav-profile-tab" data-bs-toggle="tab" data-bs-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>
<button class="nav-link" id="nav-contact-tab" data-bs-toggle="tab" data-bs-target="#nav-contact" type="button" role="tab" aria-controls="nav-contact" aria-selected="false">Contact</button>
  </div>
</nav>
<div class="tab-content" id="nav-tabContent">
  <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">...</div>
  <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">...</div>
  <div class="tab-pane fade" id="nav-contact" role="tabpanel" aria-labelledby="nav-contact-tab">...</div>
</div>
MUlferts
  • 1,310
  • 2
  • 16
  • 30
1

In case you want a vanilla js solution for modern browser

document
    // It could also be a[data-bs-toggle="tab"]
    .querySelectorAll('button[data-bs-toggle="tab"]')
    .forEach(e => e.addEventListener("shown.bs.tab", e => console.log(e)))