Tabs

Page history last edited by Jonas Flint 8 mos ago

 

type: widget

release: 1.5

priority: -

status: complete

documentation: http://docs.jquery.com/UI/Tabs

demo: http://jqueryui.com/demos/tabs

 


 

1 - Description:

 

A tab strip is used to chunk sections of content into multiple panes that can be shown one at a time, much like the sections in a notebook. Depending on the size of the window and length of tab labels, you can create a tab view that contains between two and six to eight tabs. This rule of thumb is followed because tab strips should never wrap to multiple rows or insert horizontal scrollers for the tabs because of the poor visual connection between the tab and the pane below (yes, these have been seen in the past, but is not a good thing). If there are too many items to fit in a tab strip, consider re-grouping the tab content into fewer tabs or moving to a different navigation widget like a vertical left navigation bar or tree which can accomodate a larger number of items.

 

There is a current tab widget in the UI library that needs to be extended to allow for vertical tabs (left or right orientation):

http://docs.jquery.com/UI/Tabs

http://jqueryui.com/demos/tabs

 

Detailed tab behavior descriptions can be found for Apple OS X and Microsoft Windows.

 


 

2 - Visual Design:

 

 


 

 

3 - Functional Specifications/Requirements:

 

Options/Methods/Callbacks

  • options:
    • selected (integer, default: 0)
      • Zero-based index of the tab to be selected on initialization. To set all tabs to unselected set this option to -1 (null is deprecated).
    • deselectable (boolean, default: false)
      • When set to true, clicking a selected tab will unselect it.
    • event (string, default: "click")
      • Name of the event that is used for selecting a tab. To select on hover, use "mouseover".
    • disabled (array, default: [])
      • Array of zero-based tab indices that will be disabled on initialization. Disabled tabs cannot be selected by the selection event.
    • cookie (object, default: null (no cookie used))
      • Save the currently selected tab in a cookie. This value is then being used to determine the initially selected tab if the selected option is not defined. Requires the jQuery cookie plugin.
      • The options in this object are passed through to the jQuery.cookie method.
      • Additional option: name (string, default: UUID generated from jQuery.data method) (the cookie's name)
    • spinner (string, default: "Loading…")
      • While remote content is loading, this HTML content will be displayed in the tab title area. To disable the feature, set to an empty string.
    • cache (boolean, default: false)
      • By default, tabs that load remote content will re-request the content each time the tab is re-selected. Set this option to true to have the remote content requested only the first time and cached for subsequent selections.
    • ajaxOptions (object, default: {})
      • The options in this object are passed through to the jQuery.ajax method on remote content loads.
    • idPrefix (string, default: "ui-tabs-")
      • For generation of ids for newly added tab panels.
    • fx (object or array of 2 objects, default: (no effects used))
      • The options in this object/these objects are passed through to the jQuery.animate method.
      • If objects are given in array, the first object defines the hide, the second one the show animation being used.
    • tabTemplate (string, default: "<li><a href="#{href}"><span>#{label}</span></a></li>")
      • Template to create a new a tab label form. The placeholders #{href} and #{label} are

        are replaced with their values passed to the add method.

    • panelTemplate (string, default: "<div></div>")
      • Template to create a new tab content panel from.
  • methods:
    • select
    • load
    • add
    • remove
    • enable
    • disable
    • url
    • destroy
    • length
    • rotate
  • callbacks:
    • select (event: tabsselect (custom))
    • load (event: tabsload (custom))
    • show (event: tabsshow (custom))
    • add (event: tabsadd (custom))
    • remove (event: tabsremove (custom))
    • enable (event: tabsenable (custom))
    • disable (event: tabsdisable (custom))
  • 'ui' object:

 

Specificiations

  • Indices are generally zero-based.
  • select callback: triggers when a tab is selected by event as defined in event option or programmatically via select method. If this function returns false, the requested tab won't become selected.
  • load callback: triggers when an ajax tab successfully has loaded content, either explicitly via load method or implicitly by selecting a tab.
  • show callback: triggers when the selected tab is shown. In case of animation being defined for showing this means after the animation is complete.
  • The aforementioned callbacks are thus triggered in the following order: 1. select, 2. load (ajax tab only), 3. show.
  • add callback: triggers when a new tab has been added via add method.
  • remove callback: triggers when a tab has been removed via remove method.
  • enable callback: triggers when a tab has been enabled via enable method.
  • disable callback: triggers when a tab has been disabled via disable method.
  • There are 4 possibilities to set the initially selected tab:
    • selected option (highest priority)
    • url fragment identifier matching a tab href's fragment identifier: href="#fragment-identifier",
    • from cookie,
    • the according class attribute is already specified in HTML source: <li class="ui-tabs-selected"> (lowest priority)

A possibly arising conflict is resolved by giving each alternative a different priority, as denoted.

  • It is possible to initialize an empty tab set and add tabs later on. 

  • A selected tab cannot be deselected by selecting it a second time unless option deselectable is set to true. 

  • A selected tab cannot be disabled.

  • If the selected tab is being removed the one to the right is selected as long as it is not the last one at the same time - in this case the one to the left is selected (mimicing behavior in Firefox).

  • The type of tab (in-page vs. ajax) is determined automatically from the href attribute of the contained anchor elements - an href being solely a fragment-identfier href="#fragment-identifier" results in an in-page tab, an href pointing to an existing resource href="/path/to/resource.html" results in an ajax tab. External URIs are not supported due to security restrictions with ajax.

 

Css Classes

The following markup is used in tab implementation with added classes in bold (note this is the rendered source):

 

     Sample Markup

 

     <div style="display: block;" id="tabs" class="ui-tabs ui-widget ui-widget-content ui-corner-all">

 

     <ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">

     <li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active">a href="#tabs-1">First</a></li>

     <li class="ui-state-default ui-corner-top"><a href="#tabs-2">Second</a></li>

     <li class="ui-state-default ui-corner-top"><a href="#tabs-3">Third</a></li>

     </ul>

 

     <div id="tabs-1" class="ui-tabs-panel ui-widget-content ui-corner-bottom">Tabs 1 Panel Content</div>

     <div id="tabs-2" class="ui-tabs-hide ui-tabs-panel ui-widget-content ui-corner-bottom">Tabs 2 Panel Content</div>

     <div id="tabs-3" class="ui-tabs-hide ui-tabs-panel ui-widget-content ui-corner-bottom">Tabs 3 Panel Content</div>

 

     </div>

 

     List of Classes - and Explaination:

 

     In the Container Div:

     ui-tabs -

     ui-widget -

     ui-widget-content -

     ui-corner-all -

 

     In the Unordered List that makes up your Tabs:

     ui-tabs-nav -

     ui-helper-reset -

     ui-helper-clearfix-

     ui-widget-header-

     ui-corner-all

 

      In the List tags themselves (these are your actual tabs):

     ui-state-default - 

     ui-corner-top -

     ui-tabs-selected -

     ui-state-active -

 

     In Panels that contain your content:

     ui-tabs-hide -

     ui-tabs-panel -

     ui-widget-content -

     ui-corner-bottom -

         

 

Changes from 1.5, 1.6rc5 in refactor

  • setting all tabs to unselected via value -1 instead of null (deprecated)

 

4 - Markup & Style:

 

4.1 Initial markup examples

 

     (Pre-enhanced HTML markup structure that will be transformed into the final widget. There may be multiple possible HTML markup options per widget: for example, for a slider, radiobuttons, inputs or selects could all be used. )

 

4.2 Recommended transformed HTML markup demo with html and css (live view of svn):

 

View Demo Page: http://jquery-ui.googlecode.com/svn/trunk/tests/static/tabs/tabs.html

 

 

 

 

     (The HTML markup structure and classes that will be used by the scripts in the enhanced version) 

 

4.3 Markup & style browser QA status

 

As of 12/12/08, static markup for this widget renders correctly in the following browsers.  (Correct rendering = true to design, with only small differences across browsers owing to differences in support of rounded corners, and native OS form element and font rendering.)

 

Please update this list as more browsers / platforms are tested.

 

 

XP         

Vista     

Mac 10.5

IE 6

 

 

 

 

IE 7

 

 

 

IE 8 beta

 

 

 

Firefox 2.0.0.18

 

 

 

Firefox 3.0.4

 

 

 

Safari 3.2

 

 

 

Opera 9.1

 

 

 

 

Opera 9.62

 

 

 

 

Chrome 1.0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

4.4 Accessibility recommendation

 

(Detailed recommendations for ARIA, HTML markup, CSS and javascript that will contribute to universal access and full section 508 accessibility for screen readers, mobile devices and any other devices) 

 

Fluid improvement to jQuery UI tabs

 

4.5 CSS & Theme

 

(Description of the CSS classes to be used for all states, how custom theming and Themeroller support will work.) 

 


 

5 - Latest version of plugin:

 

http://code.google.com/p/jquery-ui/source/browse/tags/latest/ui/ui.tabs.js

 


 

6 - Open issues being discussed

 

(Use this area to place things that we're hashing out like featuresand options we're not sure we should include, questions about how this fits into UI and relates to other widgets and utilities, known problems, whether features should be broken across multiple releases, etc.)

 


 

 

 

 

Comments (26)

profile picture

Richard D. Worth said

at 9:11 am on Dec 13, 2008

Should ui-tabs-hide be ui-helper-hidden? Is there any reason it needs to be tabs-specific?

profile picture

scottjehl said

at 9:56 am on Dec 13, 2008

Seems it should have both, assuming it had the ui-tabs-hide class in previous releases. I'm not thrilled about the redundancy, but it follows what we're doing on other components with the addition of framework classes. Also, widget CSS needs a way to refer to elements without using the framework states (right?).

profile picture

Richard D. Worth said

at 10:06 am on Dec 13, 2008

My first thought was that it should be renamed ui-tabs-hidden instead of ui-tabs-hide, for consistency with the framework classes. With as much as is already breaking in this release, I will tend toward cleanliness and consistency rather than backwards compatibility. But the more I thought about it, I can't see a use case for having a specific tabs-hidden class. It's just hidden. It's not hidden in some tabs-specific way. Or I guess that was my question ;) I think it's different than a case like disabled. Since disabled is a visible state, I think it's important to have both ui-draggable-disabled and ui-disabled (as an example). That way you can set a global disabled style with a widget specific override.

profile picture

Richard D. Worth said

at 10:10 am on Dec 13, 2008

As far as consistency with other widgets, this is the only widget specific -hide or -hidden I saw, though other plugins hide things. Like accordion.

profile picture

Jörn Zaefferer said

at 11:28 am on Dec 13, 2008

Accordion currently uses display:none, which probably should be replaced with ui-helper-hidden.

profile picture

scottjehl said

at 1:53 pm on Dec 13, 2008

Is there a reason we shouldn't use ui-helper-accessible-hide in these situations? Animation could complete and then that class could be added and inline styles stripped. Unless toggling display is actually the preferred behavior by the accessibility team... I'm not sure on this - any thoughts?

profile picture

Scott González said

at 3:23 pm on Dec 13, 2008

There's no need to keep the content available to AT when the tabs are closed. Providing the proper ARIA semantics will let screen readers know when content is being shown and hidden, and the content is always findable because the headers are always visible.

profile picture

kpitn said

at 3:20 pm on Jan 13, 2009

Actually fxAutoHeight is no more an option of tabs, are you considering re integrate this option ?

profile picture

Klaus Hartl said

at 11:43 am on Jan 25, 2009

Remember that it's not only about screen readers but also the ability to print.

profile picture

Jonas Flint said

at 6:51 pm on Feb 3, 2009

I've realized that tab sets on a web page can no longer be separately themed as of rc6 . Before you were able to separate theming of tabsets by declaring new defaults for a particular tab set. Example:

Tab Set 1:

$("#miniTab > ul").tabs();


Tab Set 2:

$("#mainTab > ul").tabs (
defaults = {
navClass: 'ui-tabs-nav-main',
selectedClass: 'ui-tabs-selected-main',
unselectClass: 'ui-tabs-unselect-main',
disabledClass: 'ui-tabs-disabled-main',
panelClass: 'ui-tabs-panel-main',
hideClass: 'ui-tabs-hide-main',
loadingClass: 'ui-tabs-loading-main'
}
);

If everything id drawing from the same set of classes, how can tab set themes change?

profile picture

Richard D. Worth said

at 8:59 pm on Feb 3, 2009

These options have been removed. If you want to do the same now, you use the standard class names, and just scope it with an id or a class, like so
#mainTab .ui-tabs-nav li { /* custom css */ }
#otherTab .ui-tabs-nav li { /* custom css */ }

profile picture

Jan V said

at 3:48 pm on Jun 1, 2009

If I understand it correctly 'ui-state-active' should be applied upon mousedown and should be removed on mouseup. Otherwise we don't have a state for mousedown. Tabs keep the active state upon click. And Accordion even uses the active state to indicate selected.
I find this inconsistency when I wanted to implement buttons clicks. Tabs, Accordion etc. should remove active state on mouseup and Accordion should use own 'ui-accordion-selected'. Now here is the other issue. Selected uses 'ui-selected'. Should we have general (and reusable) 'ui-state-selected' and each widget could customize it to its needs. Or the' tabs-selected', 'accordion-selected' approach is better.

profile picture

sompylasar said

at 4:54 am on Jun 3, 2009

For my Ribbon (based on ui.tabs) I need an event when tabs are collapsed (to be able to collapse the ribbon).

profile picture

sompylasar said

at 5:02 am on Jun 3, 2009

And, consequently, the 'restored' or 'expanded' event.

profile picture

Scott González said

at 6:39 am on Jun 3, 2009

can't both of these actions be detected via the select and show events?

profile picture

sompylasar said

at 3:41 pm on Jun 4, 2009

For sure, that is what I do now by checking all the panels for visibility/invisibility:

if (!self.element.hasClass(uiRibbonClasses.ribbonMinimizedClass) && !self.$panels.is(':visible')) {
self.element.addClass(uiRibbonClasses.ribbonMinimizedClass);

self._trigger('minimized', null, createEventArgs());
}

But, these complex checks may be avoided if the corresponding event is triggered from the line of code in the ui.tabs that definitely knows a collapse/expand occured.

Am I missing a simpler solution?

profile picture

sompylasar said

at 3:44 pm on Jun 4, 2009

Other nessesary event is tab-deselect (opposite to tab-select).

By not having this and previously mentioned obvious events I have to duplicate the underlying control's logic. That's no good.

profile picture

Scott González said

at 6:03 pm on Jun 4, 2009

$('#tabs').bind('select', function(event, ui) {
var opening = ui.index,
closing = $(this).tabs('option', 'selected');
if (opening == closing) {
// collapsing the currently open tab
} else if (closing == -1) {
// opening after all panels have been collapsed
} else {
// changing tabs
}
});

profile picture

sompylasar said

at 7:05 pm on Jun 4, 2009

Thanks! I'll use this.

profile picture

sompylasar said

at 11:04 am on Aug 15, 2009

On Opera 9.65 (Win) ui.tabs sortable demo at http://jqueryui.com/demos/tabs/#sortable behaves glitchy: after drag the dropped tab jumps right and slightly down.
Please, test this case.

profile picture

sompylasar said

at 11:08 am on Aug 15, 2009

profile picture

Matt Smith said

at 2:17 am on Sep 18, 2009

Any thought being given to adding left right buttons or tab width shrinking if there are more tabs than will fit on one line?

profile picture

Jason Iles said

at 1:50 pm on Sep 18, 2009

I've been trying to work on something like that. I got left/right scrolling to partially work but it changed the style since the ul was wrapped in an element with overflow:hidden. I've since tried implementing your idea of shrinking tabs. Still very early on and ugly, but the concept may be a start. http://daersystems.com/jquery/uitabs/

profile picture

Matt Smith said

at 5:25 am on Sep 24, 2009

I like that it's good work - regards the buttons maybe one of the carousel plugins mentioned under the carousel widget would work?

profile picture

Matt Smith said

at 7:28 am on Oct 22, 2009

Is there any reason why the tabs widget does not include the fillspace option that the accordian has?

You don't have permission to comment on this page.