diff --git a/docs/_includes/js/tabs.html b/docs/_includes/js/tabs.html
index 39c244e8e4d2083b759584e7cfafde7924b23384..570e21e201686beda0ae3bb13150bf46287ed06d 100644
--- a/docs/_includes/js/tabs.html
+++ b/docs/_includes/js/tabs.html
@@ -132,6 +132,14 @@ $('#myTab li:eq(2) a').tab('show') // Select third tab (0-indexed)
          <td>shown.bs.tab</td>
          <td>This event fires on tab show after a tab has been shown. Use <code>event.target</code> and <code>event.relatedTarget</code> to target the active tab and the previous active tab (if available) respectively.</td>
        </tr>
+       <tr>
+         <td>hide.bs.tab</td>
+         <td>This event fires immediately when a new tab is to be shown and before the <code>show.bs.tab</code> event. Use <code>event.relatedTarget</code> to target the new tab.</td>
+       </tr>
+       <tr>
+         <td>hidden.bs.tab</td>
+         <td>This event fires after a new tab is shown and before the <code>shown.bs.tab</code> event. Use <code>event.relatedTarget</code> to target the new tab.</td>
+       </tr>
       </tbody>
     </table>
   </div><!-- /.table-responsive -->
diff --git a/js/tab.js b/js/tab.js
index d7023c8170faaee8731d318a7b552d92331614aa..c597d7ab6b7e346b0129701a0c17093cccdcdca7 100644
--- a/js/tab.js
+++ b/js/tab.js
@@ -33,22 +33,30 @@
 
     if ($this.parent('li').hasClass('active')) return
 
-    var previous = $ul.find('.active:last a')[0]
-    var e        = $.Event('show.bs.tab', {
-      relatedTarget: previous
+    var $previous = $ul.find('.active:last a')
+    var hideEvent = $.Event('hide.bs.tab', {
+      relatedTarget: $this[0]
+    })
+    var showEvent = $.Event('show.bs.tab', {
+      relatedTarget: $previous[0]
     })
 
-    $this.trigger(e)
+    $previous.trigger(hideEvent)
+    $this.trigger(showEvent)
 
-    if (e.isDefaultPrevented()) return
+    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
 
     var $target = $(selector)
 
     this.activate($this.closest('li'), $ul)
     this.activate($target, $target.parent(), function () {
+      $previous.trigger({
+        type: 'hidden.bs.tab',
+        relatedTarget: $this[0]
+      })
       $this.trigger({
         type: 'shown.bs.tab',
-        relatedTarget: previous
+        relatedTarget: $previous[0]
       })
     })
   }
diff --git a/js/tests/unit/tab.js b/js/tests/unit/tab.js
index 8e50614ecce74b4a33c11beddf56571a0f64e378..6fbf36c50b86b24403c8ff4e8eb4115458a49de1 100644
--- a/js/tests/unit/tab.js
+++ b/js/tests/unit/tab.js
@@ -101,4 +101,81 @@ $(function () {
         .bootstrapTab('show')
   })
 
+  test('should fire hide and hidden events', function () {
+    stop()
+
+    var tabsHTML = '<ul class="tabs">'
+        + '<li><a href="#home">Home</a></li>'
+        + '<li><a href="#profile">Profile</a></li>'
+        + '</ul>'
+
+    $(tabsHTML)
+      .find('li:first a')
+        .on('hide.bs.tab', function () {
+          ok(true, 'hide event fired')
+        })
+        .bootstrapTab('show')
+      .end()
+      .find('li:last a')
+        .bootstrapTab('show')
+
+    $(tabsHTML)
+      .find('li:first a')
+        .on('hidden.bs.tab', function () {
+          ok(true, 'hidden event fired')
+          start()
+        })
+        .bootstrapTab('show')
+      .end()
+      .find('li:last a')
+        .bootstrapTab('show')
+  })
+
+  test('should not fire hidden when hide is prevented', function () {
+    stop()
+
+    var tabsHTML = '<ul class="tabs">'
+        + '<li><a href="#home">Home</a></li>'
+        + '<li><a href="#profile">Profile</a></li>'
+        + '</ul>'
+
+    $(tabsHTML)
+      .find('li:first a')
+        .on('hide.bs.tab', function (e) {
+          e.preventDefault()
+          ok(true, 'hide event fired')
+          start()
+        })
+        .on('hidden.bs.tab', function () {
+          ok(false, 'hidden event fired')
+        })
+        .bootstrapTab('show')
+      .end()
+      .find('li:last a')
+        .bootstrapTab('show')
+  })
+
+  test('hide and hidden events contain correct relatedTarget', function () {
+    stop()
+
+    var tabsHTML = '<ul class="tabs">'
+        + '<li><a href="#home">Home</a></li>'
+        + '<li><a href="#profile">Profile</a></li>'
+        + '</ul>'
+
+    $(tabsHTML)
+      .find('li:first a')
+        .on('hide.bs.tab', function (e) {
+          equal(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget')
+        })
+        .on('hidden.bs.tab', function (e) {
+          equal(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget')
+          start()
+        })
+        .bootstrapTab('show')
+      .end()
+      .find('li:last a')
+        .bootstrapTab('show')
+  })
+
 })