Dear screenreader-user, please let me know, if I can make any improvements for your convinience. Mail me to "n" dot "company" at "mac" dot "com". Thank you.
Skip to the navigation. / Zur Navigation springen. Skip to the search. / Zur Suche springen. Skip to the content. / Zum Inhalt springen. Skip to the bottom. / Zum Ende springen.
Fullscreen-Modus einschalten um die Artikel besser lesen zu können.
Update: I have created a new page dedicated to xaseTabs: xaseTabs.noelboss.ch
Today I released my «Xtensible And Simple Evented Tabs» Plugin on jQuery.com. This plugin does one thing – and one thing very good: creating tab functionality. It does not provide any styling or has any superfluous effects but instead focuses on extensibility and flexibility.
By default, the xaseTabs plugin turns a list of elements and a bunch of div’s into a tab module:
<div> <ul class="tabs"> <li>Tab 1</li> <li>Tab 2</li> <li>Tab 3</li> </ul> <div> Panel 1 </div> <div> Panel 2 </div> <div> Panel 3 </div> </div>
All you need to do, to have this behave as tabs, are the following lines of code:
$(document).ready(function(){
$('.tabs').xaseTabs();
});
The plugin is based on custom events which can be extended or overwritten without any changes of the plugin itself. The possibilities are endless; adding ajax to load the panel content, triggering a lightbox-resize after activating a tab, using the tabs as process-navigation and prevent clicks to the next steps… It’s all in your hands. Additionally you can provide some options as an object to customize the behavior of the plugin without writing you own extension.
You can download xaseTabs from google code. Then go ahead and include your copy of jQuery and xaseTabs at the bottom of your page. Replace the path of the xaseTabs Plugin with whatever folder you have put the plugin in. Then, add you custom code to initialize the xaseTabs:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"> </script>
<script src="http://www.yourserver.com/js/jquery.xaseTabs.latest.js" type="text/javascript"> </script>
<script type="text/javascript">
$('.tabs').xaseTabs({
extend: xaseTabsExtension
});
</script>
You can also checkout a working copy from the xaseTabs SVN Repository.
xaseTabs comes with a set of options to allow maximum flexibility – besides the ability to rewrite nearly the entire plugin via custom events. You can alter the defaults by providing your options as an object to xaseTabs:
$('.tabs').xaseTabs({
tabSelector: 'li a',
activeClass: 'act',
autoInitialize: false
});
xaseTabs is based on custom events – that’s why it’s so extensible. The custom events life inside a private customEvents object:
var customEvents = {
initialize: [function(options) {
this.bind("initialize." + options.namespace,
function(e) {
// ...
});
}],
setupPanels: [function(options) {
this.bind("setupPanels." + options.namespace,
function(e) {
// ...
});
}],
setupTabs: [function(options) {
this.bind("setupTabs." + options.namespace,
function(e) {
// ...
});
}],
activate: [function(options) {
this.bind("activate." + options.namespace,
function(e, selected) {
// ...
});
}]
};
For a detailed description of this functions, read the next chapter “Custom Events – here to serve you“. Those events will be bound onto the calling element upon initialisation. Before the binding happens, you can extend that array and add your own functions or disable the default functions altogether with e.preventDefault(); How would you do this? Simply create a function that gets the “customEvents” object passed and add this to the configuration object inside the “extend” key. Within the customEvents object you can push or unshift new functions into the function arrays. Lets say you have the Tabs-Plugin inside a lightbox – and that lightbox should adapt the size of the panel upon changing a tab. You would simply insert a function that calls the resize function after the default activate function has been triggered. So you push a function to the end of the customEvents.activate array that will be called after the tab has been activated:
// Create a functions that receives the customEvents
var xaseTabsExtension = function(customEvents){
// Select the desired function and add functionality:
customEvents.activate.push(function(options) {
// Bind your new extension to the Element that calls
// the tabs (not the individual tabs!)
this.bind("activate." + options.namespace,
function(e, selected) {
// Do whatever you like upon the "activate"
// event has been triggered
$.fancybox.resize();
});
});
// don't forget to return the modified event Object
return customEvents;
}
After you have done so, you can call the xaseTabs function and pass this function withhin your options-object inside the extend key:
$('.tabs').xaseTabs({
extend: xaseTabsExtension
});
If you’d like to add ajax functionality, you would unshift (instead of push) the customEvents.activate array, and add this ajax-function before the default function to loads the content dynamically…
For the concept behind evented progarming, read this article by Yehuda Katz.
The xaseTabs plugin has four events that you can extend. In every event, you have the following variables at hand:
Handles the initialization of the plugin: finding the panes and tabs, and triggering the setup events and activate the initial tab:
initialize: [function(options) {
this.bind("initialize." + options.namespace,
function(e) {
if (e.isDefaultPrevented()) {
return;
}
// caching an get cached elements from tabs-element
var $t = $(this);
var $tabs = $(options.tabSelector, $t);
var $panels = $(options.panelSelector, $t);
var $selected = $tabs.filter('.' + options.activeClass).eq(0);
// We cache the tabs and the panels directly onto the element so with
// $(this).data('$tabs') you always know what your tabs and panels are...
$t.data('$panels', $panels).data('$tabs', $tabs);
// setting up individual tabs
$t.trigger("setupPanels." + options.namespace);
// setting up individual panels
$t.trigger('setupTabs.' + options.namespace);
/**
* check for a hash like this: #xaseTabsTABID-2 where TABID is the Class of this tab-module
* and the number behind the - the Tab to be activated
*/
var hash = window.location.hash.split(options.namespace);
if ($.isArray(hash)) {
for (var i = hash.length - 1; i > 0; i--) {
// loop trough all modules
var module = hash[i].split('-');
// get Tab number and Module ID
if ($t.is(options.hashAttribute + module[0])) {
// if we are the the current module
// update selected Element and add class active
$selected = $(this).data('$tabs').removeClass(options.activeClass).eq(module[1] - 1).addClass(options.activeClass);
}
}
}
// search for predefined activate Elements
$selected = $selected.length < 1 ? $tabs.filter("[" + options.activeAttribute + "=" + options.activeAttribute + "]").eq(0) : $selected;
if ($selected.length < 1) {
// If no element selected, we activate Tab 1
$selected = $tabs.eq(0);
}
// trigger activate Event
if ($selected.length > 0) {
$t.trigger("activate." + options.namespace, $selected);
}
});
}]
Saves the panel to the according tab:
setupPanels: [function(options) {
this.bind("setupPanels." + options.namespace,
function(e) {
if (e.isDefaultPrevented()) {
return;
}
var $t = $(this);
var $tabs = $t.data('$tabs');
var $panels = $t.data('$panels');
$tabs.each(function(i) {
$(this).data('$panel', $panels.eq(i));
});
});
}]
Binds the custom activate event to the tabs. You can configure, what event triggers the activate-event via the options.triggerEvent option:
setupTabs: [function(options) {
this.bind("setupTabs." + options.namespace,
function(e) {
var $t = $(this);
var $tabs = $t.data('$tabs');
$tabs.bind(options.triggerEvent + "." + options.namespace,
function() {
$t.trigger("activate." + options.namespace, $(this));
return false;
});
});
}]
This event deactivates all tabs and activates the selected tab. You get a special variable selected that contains the selected tab:
activate: [function(options) {
this.bind("activate." + options.namespace,
function(e, selected) {
if (e.isDefaultPrevented()) {
return;
}
var $t = $(this);
var $selected = $(selected);
$t.data('$panels').hide();
$t.data('$tabs').removeClass(options.activeClass);
$selected.data('$panel').show();
$selected.addClass(options.activeClass);
});
}]
If you have any feedback, go ahead and leave a comment, or write me an e-mail to “jquery at noelboss . ch”. If you would like to see a feature added, or if you have found a bug, let me know…
If you have written a cool extension for the xaseTabs plugin – let’s say it now produces coffee on every tab-click –then, send me a copy in order that I can link it here! Some ideas for extension:
» How do I manually activate a Tab?
Just select the Tab and call the click event (or whatever event you configured with options.triggerEvent)
$(.tabs li:eq(3)).click();
» How is this accordion thing done on this page?
With the xaseTabs-plugin – of-course…
$(document).ready(function(){
var xaseTabsExtension = function(customEvents) {
customEvents.activate.unshift(function(options) {
this.bind("activate."+options.namespace,
function(e, selected) {
e.preventDefault();
var $t = $(this);
var $selected = $(selected);
var $panel = $selected.data('$panel');
$t.data('$panels').not($panel).slideUp();
$panel.slideDown();
$t.data('$tabs').removeClass("active");
$selected.addClass("active");
});
});
return customEvents;
};
$('.tabs').xaseTabs({
extend: xaseTabsExtension
});
});
» Why don’t you add (insert your feature here) feature to the plugin?
xaseTabs is so extensible that you would be better of implementing that specific feature by yourself – I want to keep xaseTabs lean and clean. If you have a cool extension to this plugin, go ahead and comment or send me an e-mail or leave a comment…
» What does «xase» mean?
eXtensible And Simple Evented. It’s based on “evented programing“
» How can I contact you?
Write a comment or send me an e-mail to jquery at noelboss . ch
» xaseTabs is so cool, can I donate some money?
Course you can – go ahead!
Juli 19th, 2010 at 21:27
The tab work is freakin bad ass. Attempted 5 different plug-ins before this. Thanks much. Let me know if you need help with bitch work. Owe you one.
Juli 19th, 2010 at 22:17
Rory, pleased to hear that you like the plugin. Let me know if you need any help or have any suggestions for improvements. If you added some useful extensions to the plugin, please send it too. What version did you use and how did you learn about xaseTabs? Version 0.2.1 has some bugfixes. I might still have an IE6 issue with a-tags… Greetings, Noël
Juli 20th, 2010 at 10:40
I have just released a new version (0.2.2 Beta) that fixes an IE6 bug and moved the xaseTabs Source over to google-code. I plan to release a new version soon that includes an $.xaseTabs.extend() function to extend the plugin for all tab instances. The goal would be to provide extensions as files that directly extend the plugin with no further code needed – just include the extension-file after the plugin and the plugin gets the new functionality.
Juli 23rd, 2010 at 21:03
Very simple to use and works well! Thanks!
I do have one question…
If I’m using this in a scenario where tabs/panels can be added dynamically, what is the best way to handle this? I don’t think I can just do
$(‘.tabs’).xaseTabs()
after tabs/panels are added.
Is there some way to “unbind” xaseTabs from the wrapped set that it has been applied to?
Thanks again!
mark
Juli 24th, 2010 at 13:57
Hi Mark
Rebinding is very simple. xaseTab Events are all namespaces so it comes down to this:
$tabs.unbind(‘.xaseTabs’);
$tabs.xaseTabs();
You could also extend the initialize event but this would be a little more effort. I have created an example for you here:
http://cl.ly/656bf90e2f748cc53f41
I plan to release a website with a lot more examples and demos and also with kind of an extension repository. I’m still thinking about a good, simple and standardized way to add and extensions to de Plugin. If anyone has some suggestions let me know. I think of something like this:
$.xaseTabs.extension.ajax{ … };
Cheers,
Noël
Juli 28th, 2010 at 20:07
Noel:
Thanks for the reply and the great example. I almost forgot that I had asked the question. That will teach me to submit comments on Friday afternoon!
One additional question, though. Using your example, I was able to unbind and rebind without trouble. However, I’m concerned about accumulating events over time, and am not sure that they are being completely unbound.
For example, if I slightly modify the xaseTabs code by putting a console.log(‘activated’); inside the activate: function, I see some strange behavior.
At first, when the page loads, clicking a tab will cause ‘activated’ to be logged to the console, once per click. If I unbind and rebind, however, each tab click will log ‘activate’ twice. If I unbind and rebind again, each tab click will log ‘activate’ three times. This will go on and on, as long as I unbind and rebind.
Does this seem like an issue to you? Any ideas?
I’ve seen this in recent versions of both Chrome and Firefox.
Thanks again,
Mark
Juli 28th, 2010 at 20:59
Just an update:
I was able to get around it by explicitly unbinding $tabs inside the xaseTabs code. Probably not the best solution.
(~ line 270)
var $tabs = $t.data(‘$tabs’);
$tabs.unbind(); // <—————added this line
$tabs.bind(options.triggerEvent + "." + options.namespace,
Juli 29th, 2010 at 07:37
Hey Mark,
Yes, one needs to unbind the Event on the individual tabs too. I’m going to release a fix for this later today.
Cheers.
August 1st, 2010 at 17:25
Hey I am trying to use it with innerfade
http://medienfreunde.com/lab/innerfade/
The inner fade is a fading banner (not within xasetab)
they don’t seem to be happy with each other.
August 9th, 2010 at 21:18
Hello Rory, please send me a link to the page you are trying to use those plugins so I can help or describe, what happens.
@ Mark, I have released Version 0.2.4 that add’s unbinding…
August 27th, 2010 at 08:28
hi noel, i have a simple structure:
tab1
tab2
content should be here after tab-click
i tried to load the content to the inner-div (in id=”newsscroller”) but failed. i used the
panelSelector: ‘~ div#newsscroller div’
in different ways (above a sample, also tried just “panelSelector: ‘div#newsscroller div’ etc.
please help me. :-) its important to load the content to these inner-divs because i just want to make the div=newscroller be scrollable, the with tabs should be fixed on screen. :-)
thank you,
matt
August 27th, 2010 at 08:30
mh, damn … the tags and stuff in my comment where deleted …
structure is this:
UL
LI=tab1
LI=tab2
/UL
DIV=#newsscroller
DIV=content from tabs here
/DIV
August 27th, 2010 at 13:50
Hey Noel,
ich bin nun ein Stück weiter, kann die “Tab”-Leiste jetzt feststehen lassen und die Daten der Tabs landen wo sie sollen, allerdings werden alle Daten (habe fünf Tabs) in jeweils komplett untereinander, innerhalb DIV#newsscroller geladen/angezeigt, innerhalb vom DIV#newsscroller gibts allerdings fünf einzelne DIVs, je eins pro Tab.
Die eigentliche Tab-Funktion ist nun durch das setzen vom Panelselector nicht mehr vorhanden, da ständig einfach alle Daten gezeigt werden. :-(
Eine Idee?
August 30th, 2010 at 09:18
Hey Noel,
um die fünf DIVs, in denen jeweils der Tab-Content angezeigt werden soll, ist ein großes, einzelnes Divs aussenherum.
Leider ist das Problem nun noch nicht gelöst. Der Content der in die verschiedenen Divs geladen werden soll, wird nur in eines geladen, und nicht aufgeteilt, somit ist die Klickfunktion auf die Tabs hinfällig, da der gesamte Content bereits angezeigt wird.
Mein Code weicht nur an der Stelle von der Vorgabe ab, dass die fünf Divs für den Content nicht direkt die nächsten Elemente nach dem Tab-Element sind, sondern ihrerseits nochmal von einem Tab umschlossen sind.
Januar 5th, 2011 at 08:01
Hey, have you got RSS on your blog? I can’t find the link.
Januar 5th, 2011 at 08:41
Yes, you’ll see it in the address-bar of your browser or – if you click on more (only visible on the main-site, not in article view) – you’ll find the links. Cheers…
August 22nd, 2011 at 14:03
I have created a new page to document the xaseTabs plugin. Please take a look at it: http://xasetabs.noelboss.ch/