-
Notifications
You must be signed in to change notification settings - Fork 17
WTabSet
WTabSet is a component used to create tabbed or accordion interfaces. Each tab is created from a WTab.
- Why use WTabSet
- Creating a WTabSet
- Accessibility
- Usability
- Types of tabset
- Tabs
- Fixing content height
- Disabling
- Hiding
- HTML output
- Margins
- WCollapsibleToggle
- Responsive design
- Related Components
- Further information
The one true answer to this is "don't". However, if an application has a need for a tabbed or accordion interface then WTabSet will do that and do it in a manner compatible with WCAG 2.0 guidelines.
WTabSet can create two separate but related UI components as determined by the type property:
-
A tab set
-
An accordion
The main differences between these are:
- A tab set has a group of openers (the tabs) and a single panel in which the content of the 'open' tab is displayed; whereas an accordion has the openers and content interleaved.
- A tab set must have exactly one tab 'open' whereas an accordion may have 0...
n
ofn
tabs open. - As a corollary to the above in a tab set opening a closed tab will always close the currently open tab and a tab may only be closed by opening another tab in the same tab set; whereas in an accordion opening and closing tabs is independent of all other tabs in the accordion (unless the single property is
true
) and an open tab may be closed directly. - The interaction models for the two components differ in important areas and if you intend to design a UI which uses a WTabSet then you should be familiar with the WAI-ARIA authoring practices for each:
WTabSet is not as good a UI tool as some seem to think but it is not worthless. If you are reading this on GitHub take a look up the top of this page: the GitHub UI is based on a tab set. This is because each segment of the UI is an independent process and a user is only expected to interact with one at a time.
A process may be a candidate for a WTabSet if:
- the user can choose to interact with the contents of every tab in the WTabSet in any order; and
- interacting with one tab has no impact on the use of any other tab; and
- the non-use of any tab does not cause a block in the flow of use of the processes in any other tab.
If an application flow causes any cross-dependencies between the process of interacting with any tab in any order then it is not a good candidate for a WTabSet.
If a requirement of moving through a process involves disabling other [tabs|WTab]] or their content as a consequence of interacting with controls in the current tab then the process does not lend itself to a tabbed interface and WTabSet should not be used.
WTabSet has two simple constructors, the default constructor will create a WTabSet of the default TabSetType.TOP. The alternative is to pass the TabSetType as an argument which must be used if a TabSetType other than the default is required.
// a default tabset (tabs on top)
WTabSet tabset = new WTabSet();
// tabs to the left of the content
WTabSet tabsetLeft = new WTabSet(TabSetType.LEFT);
// an accordion
WTabSet accordion = new WTabSet(TabSetType.ACCORDION);
The underlying structure of a tab set and an accordion has been carefully determined to provide a component which meets WCAG 2.0 AAA accessibility requirements if used unmodified. The styling of the components and the interaction controllers then use the accessibility features as the determinant of appearance and function.
It is still possible to build an inaccessible tab set by specifying non-palpable or inaccessible content as the sole content of a tab's label.
When the WTabSet outputs a tab set the tab openers are grouped into an element with a WAI-ARIA role of tablist. The tab content is output into a container with a WAI-ARIA role of tabpanel.
Keyboard navigation between tab openers in a WTabSet is outlined in this section of the WTab documentation.
A WTabSet allows content to be hidden from the user. If this content includes data input controls then it is possible that those controls will not be seen.
A user interface should never have mandatory fields in a tab which is closed when the page loads. This means that you should not design an interface that has mandatory fields on more than one tab of a tab set and preferably not design a tab set with mandatory fields on any tab.
In modern user agents a failure to complete a mandatory field may block form submission with a user-agent generated error message. If the mandatory field is in a closed tab then the user-agent generated message will not be visible to the user and the submission will appear to have silently failed for no reason.
A user interface should not use tabs to split up a set of dependent processes, i.e. any set of interactions in which the data, flow or controls of one are dependent on the state of another. Tabs may be accessed by the user in any order so are not an appropriate mechanism to control flow through a set of steps. Progressively enabling tabs is rather silly.
WTabSet can be used to create:
- a regular tabset with the tabs across the top of the content;
- a regular tabset with tabs to the left of the content;
- a regular tabset with tabs to the right of the content (though this is not recommended); or
- an accordion where the tabs and content are interleaved.
The type of tabset created is set using a TabSetType property. This property has four options:
-
TOP (default) which produces a tab set and places the tabs above the content
-
LEFT which produces a tab set and places the tabs to the left of the content
-
RIGHT which produces a tab set and places the tabs to the right of the content
-
ACCORDION which produces an accordion
The property is set only in a constructor so to set a type other than TabSetType.TOP
one would use the constructor with the TabSetType
argument:
// tabs to the left of the content
WTabSet tabset = new WTabSet(TabSetType.LEFT);
// an accordion
WTabSet accordion = new WTabSet(TabSetType.ACCORDION);
An accordion is a variant of a tabset in which the tabs and content are interleaved. This is most commonly a vertical interleaving, which is the default in WComponents, but could easily be made a horizontal interleaving in a theme.
An accordion is created by using the TabSetType.ACCORDION in the constructor for a WTabSet.
// Create an accordion
WTabSet accordion = new WTabSet(TabSetType.ACCORDION);
An accordion, by default, may have more than one tab open at a time. Many other implementations allow only one tab to be open at a time, but consider how a piano accordion works: the air moves through the instrument by expanding and contracting bellows. If an accordion could only have one part of its bellows open at a time it would not expand and contract; it would simply move side to side.
We acknowledge, however, that there are cases where wheat is needed is not an actual accordion but a semi-accordion with a single tab open and the same sort of auto-closing as in a regular tabset. To this end any instance of an accordion WTabSet may be set to force single tab open by using the single
property.
// With WTabSet `accordion`
// to force only one tab open at a time:
accordion.setSingle(true);
// to allow multiple tabs to be open:
accordion.setSingle(false);
// note though that this is the default
// so does not normally have to be set
// explicitly.
Each WTab is added to a WTabSet using add(WTab)
. Each WTab's rendering, visibility, content loading mode and disabled state is able to be manipulated individually. The disabled state of tabs will, however, inherit the disabled state of the WTabSet to which they are added.
// add a WTab `tab` to WTabSet `tabset`
tabset.add(tab);
Instances of WTab may be created whilst adding the WTab to a WTabSet using addTab
. The arguments of the various overloaded addTab
method reflect those of WTab's constuctors.
// add a LAZY tab with a terrible name:
WTab poorlyNamedTab = tabset.addTab(
someContentComponent, "tab label", TabMode.LAZY);
An individual WTab added to a WTabSet may be accessed by its index in the list, and the index may be obtained if there is a handle to the WTab's content component.
// using WTabSet `tabset` and known content
// component `content`
// get the index of the tab which has that content
int idx = tabset.getTabIndex(content);
// then get the WTab at that index
WTab tabWithContent = tabset.getTab(idx);
// it is a bit convoluted...
There is also a method to get the total number of WTabs added to a WTabSet.
// with WTabSet `tabset`
int numberOfTabs = tabset.getTotalTabs();
The open WTab is usually determined programmatically based on user interaction. The default open WTab for first presentation of the WTabSet may be set using setActiveIndex(int)
or setActiveTab(WTab)
if the WTabSet may have only one tab open or setActiveIndices(int[])
if the tabset is an ACCORDION
and may have multiple (or zero) tabs open unless the single property is set true`.
// force an accordion to have no more than one tab open at a time
// with WTabSet `accordionTabSet`
accordionTabSet.setSingle(true);
Note that if more than one WTab is set to be open on load for instances of WTabSet which do not support multiple open tabs only one will be deemed to be open and there is no guarantee which one will be open.
If a WTabSet's active tab is not set then it will default to the first WTab in the WTabSet which is in a state which will be rendered and is not hidden in the UI - even if that WTab is in a disabled state.
The active tab(s) in a WTabSet may be accessed as indices or WTabs.
// with tabset `tabset`
// the index of the currently active WTab
int activeIndex = tabset.getActiveIndex();
// the currently active WTab
WTab activeTab = tabset.getActiveTab();
// with ACCORDION `accordion`
// the indices of tabs currently active
List<integer> indices = accordion.getActiveIndices();
// the list of active WTabs
List<WTab> activeTabs = accordion.getActiveTabs();
Note that with a multi-selectable accordion getActiveIndex()
will return the index of the first (in tree order) active WTab and getActiveTab()
will return the first (in tree order) active WTab (if any). Equally, for all other types and states of WTabSet getActiveIndices()
and getActiveTabs()
will return Lists containing no more than one entry.
A fixed height for the content panel(s) (the tabpanel
role) of a WTabSet may be enforced using the contentHeight
property. If the content of the tab exceeds the set height the tab will be internally scrollable as shown in the illustration below.
The contentHeight
is a String property and it is incumbent on the developer to ensure the value set has a meaning in CSS.
WTabSet tabset = new WTabSet(TabSetType.LEFT);
// this will fix the height of tabs:
tabset.setContentHeight("15em");
// this will cause nothing but merriment to those
// looking at your application source
tabset.setContentHeight("really_big");
If a WTabSet with TabSetType of LEFT
or RIGHT
has a fixed content height, and that content height is less than the height of the tabs, the tabset may look very strange. If the content height is not fixed then the minimum height of the tabpanel
elements will be the combined height of the tabs and spacing.
A WTabSet may be disabled on page load. When disabled the WTabSet will not respond to user input or interaction. No WTab in the WTabSet will respond to user interaction. Form controls in the content of open tab(s) are not automatically disabled by disabling the WTabSet.
This property may be used in conjunction with WSubordinateControl controls to enable or disable content without making another server call. Individual WTabs may also be disabled and it is hard to make an argument for disabling a complete WTabSet. This property is, therefore, under review.
// given WTabSet `tabset`
// make it disabled
tabset.setDisabled(true);
A WTabSet may be hidden on page load. When hidden the WTabSet is not available to any compliant user agent. It is present in the source and is not obscured in any way. This property is determined by a WSubordinateControl. When a WTabSet is hidden all of its WTabs and their content are also hidden.
The wrapper element of a WTabSet if a div element. WTabSet must not be placed in any container WComponent which may only contain phrasing content.
WTabSet is a marginable component.
A WTabSet with TabSetType.ACCORDION
may be the target of a WCollapsibleToggle. This allows all of the WTabs in the tabset to be opened or closed with a single interaction. This is not consistent with an accordion which is set to only allow one tab to open at a time. If such a WTabSet is made the target of a WCollapsibleToggle then collapsing all tabs will close the only open tab but expanding all tabs will only result in the last visible, enabled tab being opened - which is a bit pointless.
To have a WCollapsibleToggle control an accordion, the accordion is added to a CollapsibleGroup.
// with WTabSet `tabset` and CollapsibleGroup `group`
tabset.setGroup(group);
The arrangement of tabs in a WTabSet may result in sub-optimal rendering on small screens if the TabSetType is not ACCORDION
. To overcome this the following responsive design aspects are built in to WComponents but may be overridden using [application level CSS|Adding custom CSS]].
- When the viewport width is 1000px or below TabSetType
LEFT
andRIGHT
are rendered with the tabs on top of the content as per TabSetTypeTOP
. - When the viewport width is 773px or below then all TabSetTypes are rendered as accordions. WTabSets which are not of TabSetType
ACCORDION
are all treated as single-opening accordions and are restored to their former TabSetType if the viewport width subsequently returns to greater than 773px.
More information, including information regarding customising responsive design, can be found in Responsive design.