eBay

Combobox

Select phone model item specifics

Introduction

An enhanced textbox that allows free text input, selection from a list, or a combination of both. Hence the name 'combobox'.

A combobox is a composite pattern containing a textbox, listbox and button.

A combobox may optionally have autocomplete behaviour.


Updates

  • Feb 22nd, 2016
    • Issue with Safari and Voiceover not announcing combobox options is now fixed.
  • May 13th, 2016
    • Developer Guide added
  • Oct 12th, 2017
    • Added offscreen live-region to combat new issue with VoiceOver

Working Example

You can take a look at the combobox pattern in action on our examples site.

You can get an idea of the required markup structure by viewing our bones project.


Best Practices

Each row in the list of options allows only a single action. It is not possible to have multiple actions per row, e.g. select, edit and delete.


Interaction Design

Keyboard

Combobox keyboard focus will appear to be in two places at the same time (the textbox and the listbox). In actual fact, keyboard focus always stays on the textbox. The aria-activedescendant property controls the pseudo-focus inside of the listbox.

With keyboard focus on the combobox, down arrow key will expand the listbox.

Alternatively, you may wish to auto-expand the listbox as soon as focus lands on the combobox. In this case, you may wish to exclude the button.

There is no strict requirement for the combobox button to be in the keyboard tabindex. This is because the listbox can be expanded using the down arrow key.

Up and down arrow keys navigate the list of options.

Pressing ENTER key on any option will set the combobox value and close the list of options.

Pressing ESC key will close the listbox if visible, otherwise clear the textbox value.

Screen Reader

The screen reader will announce the input as 'text edit', 'combobox' or words to those effect, depending on level of ARIA support.

When keyboard focus is on the textbox, screen reader should announce "Combobox has n options available. Use arrow keys to navigate options, and ENTER to select" - or words to those effect. Typically this instructional text is not always provided by screen readers and so may need to be added by the web developer.

Mouse and Touch

Clicking or tapping the combobox button will toggle the listbox display.

Alternatively, you may wish to auto-expand the listbox when tapping inside the combobox input.

Clicking or tapping an option will fill the combobox with that value. For long forms, the list of options must close without triggering form submit.


Developer Guide

Combobox is a good example of progressive enhancement. Until JavaScript is loaded or initalised, the textbox operates as a regular textbox. For example, a user can still enter and submit a value using the plain old textbox. The ability to choose a value from a list of pre-defined options is considered the enhancement that will be available with JavaScript.

Textbox

We start with a label and textbox:

<span class="combobox" id="combobox-0">
  <label for="combobox-0-input">Game Console</label>
  <input id="combobox-0-input" name="console" type="text" placeholder="Playstation 4, Xbox One, etc."/>
  <!-- button will go here -->
  <!-- description will go here -->
  <!-- listbox options will go here -->
</span>

We have added our elements inside of a .combobox wrapper element. This wrapper acts as our module root and hook for CSS & JavaScript.

Remember: the textbox does not yet have a role of combobox, it is added later with JavaScript.

A button, description and listbox elements will be appended to this wrapper. It is up to you whether you wish to render these elements server-side or client-side. There are pros and cons to both approaches, which we will discuss below.

Button

The button should immediately follow the textbox. This button allows mouse and touch users to expand the combobox.

<button type="button" disabled>Expand</button>

It is sometimes useful to render this button on the server to avoid a flash of content or layout issues. If rendered on the server, the button should be in a disabled state. This is because the button is useless without JavaScript. The button can be enabled after all client-side initialisation for the widget is complete.

Description

At the time of writing, screen readers don't do a good job of letting the user know how to interact with a combobox or how many options it contains. To solve this problem, we can add offscreen text.

<span id="combobox-0-description" class="clipped">Combobox has 6 options. Use arrow keys to navigate options, and ENTER key to select.</span>

It is strongly recommended to add this description element on the client-side, and only after we are sure the widget is fully functional.

Next, in order for the screen reader to announce this description, we must add an aria-describedby attribute to the combobox. Again, this should be added using JavaScript on the client-side.

<input id="combobox-0-input" name="console" type="text" placeholder="Playstation 4, Xbox One, etc." aria-describedby="combobox-0-description" />

Now the screen reader announces the description whenever focus lands on the combobox.

Live Instructions

If the number of options changes based on the value of the combobox (i.e. filtering occurs) this new information must be related to assistive technology. The description element can be converted to a live region in order to achieve this.

<span id="combobox_0-description" class="clipped" role="status" aria-live="polite">Combobox has 6 options. Use up and down keys to navigate.</span>

The new attributes are role=status and aria-live=polite.

Note: aria-live attribute is technically redundant here, because status role has an implicit aria-live setting of polite. We add it to double-up on our support for older browsers and AT that might not support the status role.

Listbox

After the description, we add the listbox of options. The listbox may render on the server or the client. Like the disabled button above, it is wise to put the listbox in a hidden state if rendering on the server. To do so, use the hidden attribute.

<div class="combobox__overlay">
  <ul id="combobox_0-listbox" role="listbox" hidden>
    <li role="option" id="nid-0">Playstation 3</li>
    <li role="option" id="nid-1">Playstation 4</li>
    <li role="option" id="nid-2">Xbox 360</li>
    <li role="option" id="nid-3">Xbox One</li>
    <li role="option" id="nid-4">Wii</li>
    <li role="option" id="nid-5">Wii U</li>
  </ul>
  <!-- status goes here -->
</div>

Using JavaScript we now convert the textbox to a combobox, by adding role=combobox. We also create the properties and state that connect the combobox to the listbox:

<input id="combobox-0-input" name="console0" type="text" placeholder="Playstation 4, Xbox One, etc." role="combobox" aria-expanded="false" autocomplete="off" aria-owns="combobox_0-listbox" aria-describedby="combobox_0-instructions">

The new attributes are role, aria-expanded, autocomplete and aria-owns.

Keyboard and Screen Reader Navigation

Our elements are now in place, but how does a keyboard user navigate to the options? We cannot use TAB key because focus must stay on the combobox (so that user can type characters). As with mosts widgets, the answer lies in the arrow keys. Up and down arrow keys are the way to select our combobox options.

If focus must remain on the combobox, how then do we also have focus on the listbox options? The answer is that we don't. Focus always remains on the combobox and instead we have a kind of pseudo-focus on the options.

How does the screen reader know where this pseudo-focus is?

Active Descendant

We call the option with pseudo-focus the "active descendant". And guess what, there is an ARIA attribute for this called aria-activedescendant. This attribute is placed on the combobox element. The attribute value is the ID of the currently active (pseudo-focussed) option. This allows assistive technology such as a screen reader to programmatically determine

To make all of this easier, we recommend using a plugin such as jquery-active-descendant. After your HTML structure is in place, simply activate the plugin on the widget and up/down arrow keys will update the necessary states. Use CSS to style the active descendant in any way you like.

Problem #1: VoiceOver and Active Descendant

Historically, the Safari and VoiceOver combination has lacked support for the aria-activedescendant state, and this situation is still true today. To workaround this issue we create another offscreen live region and append it to the overlay.

<div class="combobox__overlay">
  <ul id="combobox_0-listbox" role="listbox" hidden>
    <li role="option" id="nid-0">Playstation 3</li>
    <li role="option" id="nid-1">Playstation 4</li>
    <li role="option" id="nid-2">Xbox 360</li>
    <li role="option" id="nid-3">Xbox One</li>
    <li role="option" id="nid-4">Wii</li>
    <li role="option" id="nid-5">Wii U</li>
  </ul>
  <div class="flyout__status" aria-live="assertive" aria-atomic="true">
    <span></span>
  </div>
</div>

When there is no active descendant, the nested span remains empty. When there is an active descendant, we populate the nested span with the value of that option, thus forcing VoiceOver to announce the live region.

<div class="combobox__status" aria-live="assertive" aria-atomic="true">
  <span>Option: Xbox 360</span>
</div>

This live region can of course be hidden offscreen, using the clipped class.

For screen readers that do support active descendant, this does mean that the value is going to be announced twice, something like:

"Xbox 360 [pause] Option 3 of 6 [pause] Option Xbox 360"

Problem #2: JAWS Keyboard Navigation

At the time of writing we have found that role of combobox does not force JAWS into application mode. This means that ARROW keys will be intercepted by JAWS, thus making UP/DOWN arrow key navigation problematic. In order to force JAWS into application mode, we apply a wrapper element with role=application.

<span role="application">
  <span class="combobox" id="combobox-0">
    <!-- label, input, description, etc -->
  </span>
</span>

We hope that this workaround will only be a temporary measure until we see better support for combobox role in JAWS.

ARIA Reference

This section gives an overview of ARIA usage, within the context of this pattern.

role=application

We have found that this wrapper role is necessary for correct behaviour of keyboard accessibility in JAWS and IE.

role=combobox

This attribute changes the role of the text input from textbox to combobox. We recommend applying this attribute on the client-side with JavaScript.

role=status

This role converts the offscreen text description/instructions into an ARIA live region.

role=listbox

The list of suggestions has a role of listbox

role=option

Each listbox item has a role of option.

aria-describedby

This property connects the combobox to the offscreen description/instructions.

aria-owns

This property connects the combobox to the listbox.

aria-expanded

Conveys the expanded state of the combobox.

aria-label

Provides the expand/collapse button with an accessible label, in the case where it has no visible text (i.e. an icon button).

results matching ""

    No results matching ""