diff --git a/js/panels_tabs.js b/js/panels_tabs.js
index 330b744..2da4349 100644
--- a/js/panels_tabs.js
+++ b/js/panels_tabs.js
@@ -8,13 +8,60 @@ Drupal.behaviors.panelsTabs = {
     var tabsID = Drupal.settings.panelsTabs.tabsID;
     
     for (var key in Drupal.settings.panelsTabs.tabsID) {  
-      $('#' + tabsID[key] +':not(.tabs-processed)', context)
-        .addClass('tabs-processed')
-        .tabs();
+      
+      // The "tab widgets" to handle.
+      var tabs = $('#' + tabsID[key], context);
+        
+        // This selector will be reused when selecting actual tab widget A elements.
+        tab_a_selector = 'ul.ui-tabs-nav a';
+      
+      // Enable tabs on all tab widgets. The `event` property must be overridden so
+      // that the tabs aren't changed on click, and any custom event name can be
+      // specified. Note that if you define a callback for the 'select' event, it
+      // will be executed for the selected tab whenever the hash changes.
+      tabs.tabs({ event: 'change' });
+      
+      // Define our own click handler for the tabs, overriding the default.
+      tabs.find( tab_a_selector ).click(function(){
+        var state = {},
+          
+          // Get the id of this tab widget.
+          id = $(this).closest( '.ui-tabs' ).attr( 'id' ),
+          
+          // Get the index of this tab.
+          idx = $(this).parent().prevAll().length;
+        
+        // Set the state!
+        state[ id ] = idx;
+        $.bbq.pushState( state );
+      });
+      
+      // Bind an event to window.onhashchange that, when the history state changes,
+      // iterates over all tab widgets, changing the current tab as necessary.
+      $(window).bind( 'hashchange', function(e) {
+        
+        // Iterate over all tab widgets.
+        tabs.each(function(){
+          
+          // Get the index for this tab widget from the hash, based on the
+          // appropriate id property. In jQuery 1.4, you should use e.getState()
+          // instead of $.bbq.getState(). The second, 'true' argument coerces the
+          // string value to a number.
+          var idx = $.bbq.getState( this.id, true ) || 0;
+          
+          // Select the appropriate tab for this tab widget by triggering the custom
+          // event specified in the .tabs() init above (you could keep track of what
+          // tab each widget is on using .data, and only select a tab if it has
+          // changed).
+          $(this).find( tab_a_selector ).eq( idx ).triggerHandler( 'change' );
+        });
+      })
+      
+      // Since the event is only triggered when the hash changes, we need to trigger
+      // the event now, to handle the hash the page may have loaded with.
+      $(window).trigger( 'hashchange' );      
     } 
   }
 };
 
-})(jQuery);
-
-
+})(jQuery);
\ No newline at end of file
diff --git a/plugins/styles/tabs.inc b/plugins/styles/tabs.inc
index aac66cd..6af47cf 100644
--- a/plugins/styles/tabs.inc
+++ b/plugins/styles/tabs.inc
@@ -30,7 +30,10 @@ function theme_panels_tabs_style_render_region($vars) {
     '#prefix' => '<div id="' . $tab_id . '">',
     '#suffix' => '</div>',
     '#attached' => array(
-      'library' => array(array('system', 'ui.tabs')),
+      'library' => array(
+        array('system', 'ui.tabs'),
+        array('system', 'jquery.bbq'),
+      ),
       'js' => array(
         drupal_get_path('module', 'panels_tabs') . '/js/panels_tabs.js' => array('type' => 'file'),
       ),
