Create an accessible combobox using ARIA

Most combo boxes we’re familiar with let the user type in a value and then it presents a list of related results.

For example in this screenshot, there’s a search text input. When I start typing “websites,” I get a list of suggested searches I could choose from.

Combo boxes are in a lot of website or app interfaces as searches, form elements, or to help filter list selections. They can make it easier for users to find what they’re looking for or make sure they input the correct value.

But, if they’re inaccessible, an entire keyboard and assistive technology user group can either be frustrated using the combo box or flat-out can’t use it.

To make a combo box accessible, certain keyboard interactions are needed for keyboard users. It also needs specific ARIA roles, states, and properties to interact correctly with assistive technology.

In this article, we’ll review how to make a combo box accessible by going over:

Types of combo boxes

Combo boxes are made of two parts. First is the box itself, which is the input. Second is the pop-up the input triggers, which is what users can select from.

The difference between combo box types is whether the combo box is editable and the type of pop-up the combo box triggers.

Editable vs non-editable

Most combo boxes we interact with are editable or let the user type a value in the combo box. Typing into the combo box is one of the key perks to creating a combo box.

An editable combo box can either:

  1. Accept any value
  2. Filter the allowed values

Non-editable combo boxes are similar to an HTML select element. If you’re creating a combo box that isn’t editable, using the HTML select element could be a simpler solution as it has accessibility already built into it.

To help you decide which option is best for your situation, review W3C’s Select-Only example. It lists accessibility and usability differences between a select-only combo box and the HTML select element.

Pop-up types

A combo box can trigger four pop-up types:

  1. Listbox: This is what we interact with most often. The pop-up is a list of suggested values.
  2. Grid: A grid pop-up is similar to a listbox as it is a list of values. The difference is the suggested values have multiple columns. For example in this screenshot, there’s the fruit or vegetable name (the suggested value) and the other column has whether it’s a fruit or vegetable (the parent group).
  3. Tree: A tree pop-up gives the user a hierarchical list to choose from. Tree widgets have their own ARIA pattern and typically represent complex parent and child relationships.
  4. Dialogue: A dialogue pop-up triggers a window to overlay the user’s primary window. For example in this screenshot, selecting the combo box triggers a date picker dialogue box.

Back to top

When to use a combo box

Now that we know what a combo box is, let’s review when to use one. In the rest of this article, we’ll focus on editable combo boxes with a list box pop-up since these are the most common.

The most common reason for using a combo box is because the user has a lot of options. 15 or more options means you should consider using a combo box. Here’s why:

  • 15 options in a dropdown, multi-select, or radio button can start to take up a lot of real estate on the screen
  • It can also be overwhelming for a user to go through that many options especially if there’s scrolling involved.

But, each situation is different – just because you have several options, doesn’t necessarily mean you need a combo box.

Remember, if you can use a native HTML, you should because it keeps it simpler and has built-in accessibility.

Example 1

Let’s review an example. In this form question, I’m asking the user what their favorite food is. They can select from ten short options. In the first option, we use radio buttons, so the user has to select one choice. In the second option, we use an HTML multiple select, so the user can select multiple favorite foods from the ten choices.

Even though there are several choices, each choice is short, so it’s not cognitively taxing to sort through the options and choose one. In situations like these, a combo box might not be necessary even though there are several options to choose from.

Example 2

In this example combo box, the user is asked to select their favorite fruit. There’s an extensive list of over 30 options.

An editable combo box makes sense in this situation because there are so many options. It doesn’t make sense to use the real estate on the screen to display that many choices plus it would be difficult for a user to sort through all those options. A combo box lets the user think of their favorite fruit and just start typing to find it.

In addition to form questions with several options, combo boxes are also great for searches. An editable combo box lets the user type the search query and review suggested searches without having to submit the query. They can select a suggested search or still type in their own unique query.

Back to top

Design considerations before coding your combo box

If you need a combo box for your situation, there are four things to consider before you start coding.

Keep it simple

To start, keep it as simple as possible when designing the interaction. The simpler it is, the easier it is to use and make accessible.

What triggers the pop-up?

Different user actions can trigger the pop-up to open. Here are some examples.

  1. Selecting the input box, pressing the down arrow, or pressing the open button opens the pop-up.
  2. The pop-up opens when the combo box has focus even if the combo box is empty.
  3. The pop-up opens after the user types a certain number of characters. If the combo box requires a specific value and the user’s string doesn’t match an allowed value, the pop-up doesn’t expand.

The best time for your pop-up to open depends on your situation user’s experience. But, most pop-ups open when selecting the input box or after the user starts typing characters.

For example, in both of these combo boxes, I didn’t type anything but selecting it still opened up a list. The first is a search input and it has a list of suggested searches. The second is a state list and it opens a state list.

In this search combo box, selecting it displays a prompt that reads type to search. But, the list box doesn’t open until I start typing characters.

Which autocomplete option should you use?

There are three autocomplete options:

  • none: No autocomplete functionality. This means that even when the pop-up is triggered, its values are the same regardless of what the user types in the combo box.
  • list: When the popup is triggered, there’s a list of suggested values. If it’s an editable combo box, the values complete or go with the characters in the combo box.
  • both: When the popup is triggered, a list of suggested values complete or go with the characters in the combo box. Plus, the rest of the focused suggestion that hasn’t been typed shows after what the user has already typed. The inline completion string is visually highlighted and has a selected state.

Back to top

Required keyboard interactions for accessibility

You’ll create these keyboard interactions using JavaScript.

This is for an editable combo box with a single select list box. Visit W3C’s Combobox pattern for more information and other pop-up types.

Remember, editable combo boxes have two parts: the type input and the pop-up. We’ll go over the keyboard interactions for the combo box input and a list box pop-up.

Editable combo box with a list box pop up listing the state names.

Combo box (input) keyboard interactions

  • Tab: The combo box is in the page’s tab order – users can tab to it in the natural sequence of the page.
    • Any pop-up icon/button, the pop-up, and its content are not in the page’s tab order.
  • Down Arrow: Opens the pop-up and moves focus to the pop-up.
    • Selecting down arrow again places focus on the first focusable element in the pop-up and so on.
    • If autocomplete selected a suggestion before the down arrow was pressed, place focus on the first suggestion after the automatically selected suggestion.
  • Up Arrow (Optional): Puts the focus on the pop-up’s last focusable element.
  • Escape: Dismisses the pop-up if it is visible.
    • Optional: If the pop-up is hidden before Escape is pressed, it clears the combo box.
  • Enter: If a suggestion has the focus in the popup, enter accepts the suggestion by placing the input cursor at the end of the value in the combobox OR by completing the default action. For example, the default action could be performing a search on that value.
  • Printable characters: Type the characters in the combo box. Some situations might consider certain characters invalid and not allow their input.
  • Supports standard single-line text editing keys. For example, control/command + A selects all the text or control/command + C copies text.
    • An easy and comprehensive approach for providing text editing functions is to rely on browsers. Browsers give text editing functions for HTML inputs with type=”text”, which an editable combo box should have.
    • IMPORTANT: Make sure your JavaScript doesn’t break browser-provided text editing by capturing key events for text editing keys.
  • Alt + Down Arrow (Optional): If the pop-up is not displayed, displays the pop-up without moving focus.
  • Alt + Up Arrow (Optional):
    • If the pop-up is displayed and has focus, puts focus back to the combo box.
    • If the pop-up is displayed, it closes the pop-up.

List box pop-up keyboard interactions

Before reviewing the keyboard interactions for a list box, let’s review what we mean by focus. DOM focus always stays on the combo box. The assistive technology focus is moved within the list box using aria-activedescendant. When we refer to focus in the keyboard interactions below, we’re referring to the assistive technology focus using aria-activedescendant.

When the focus moves to the list box, these are the needed keyboard interactions:

  • Enter: Accepts the focused option in the list box. This closes the pop-up and either places the accepted value in the combo box with the input cursor at the end of the value OR completes the default action.
  • Escape: Closes the popup and returns focus to the combo box.
    • Optional: Clears the combo box’s contents.
  • Down Arrow: Moves focus to and selects the next option. If the focus is on the last option, it either returns focus to the combo box or does nothing.
  • Up Arrow: Moves focus to and selects the previous option. If the focus is on the first option, it either returns focus to the combo box or does nothing.
  • Right Arrow: Returns focus to the combo box without closing the popup and moves the input cursor one character to the right. If the input cursor is on the right-most character, the cursor does not move.
  • Left Arrow: Returns focus to the combo box without closing the popup and moves the input cursor one character to the left. If the input cursor is on the left-most character, the cursor does not move.
  • Home (Optional): Returns focus to the combo box and places the cursor on the first character.
  • End (Optional): Returns focus to the combo box and places the cursor after the last character.
  • Any printable character: Returns the focus to the combo box without closing the popup and types the character.
  • Backspace: Returns focus to the combo box and deletes the character before the cursor.
  • Delete (Optional): Returns focus to the combo box, removes the selected state if a suggestion was selected, and removes the inline autocomplete string if present.

Back to top

Required ARIA roles, states, and properties for accessibility

The combo box’s input and list box both need certain ARIA to properly interact with assistive technology. We’ll review the ARIA needed for an editable combo box with a single select list box. We’ll also break the ARIA down again in the example below.

Visit W3C’s Combobox pattern for more information and other pop-up types.

Combo box

You’ll use JavaScript to change the state of several of these ARIA states.

  • The element that serves as an input and displays the combo box value has the role of combo box (role="combobox").
  • The combo box element has aria-controls set to a value that refers to the element that serves as the pop-up. aria-controls only needs to be set when the pop-up is visible.
    • aria-owns used to be used instead of aria-controls. It’s now suggested to use aria-controls.
  • The element with the role combo box has aria-haspopup set to list box (aria-haspopup="listbox"). Elements with role combobox have a default value of list box, so setting it for a list box pop-up is optional.
  • When the combo box popup is not visible, the element with the role combo box has aria-expanded set to false (aria-expanded="false"). When the popup element is visible, aria-expanded is set to true (aria-expanded="true").
  • When a combo box has focus, DOM focus is on the combobox element.
  • When a descendant of a list box has focus, the DOM focus stays on the combo box. The combo box has aria-activedescendant set to a value that refers to the focused element in the pop-up.
  • Selection follows focus in the list box. The list box only allows one suggested value to be selected at a time for the combo box value.
  • The combo box is labeled using one of these methods:
    • If there’s a visible label, use the HTML label element.
    • If it has a visible label, use aria-labeled by to refer to the labeling element.
    • If there isn’t a visible label, use aria-label.
  • The combo box element has aria-autocomplete set to a value that matches its autocomplete behavior.

List box

  • The pop-up is an element that has role listbox (role="listbox").
  • Each option in the list box has role option (role="option") and is owned by the element with the role list box.
  • The option containing the value that’s visually indicated as the currently selected value has aria-selected set to true (aria-selected="true").
  • If the complete set of available options is not present in the DOM due to dynamic loading as the user scrolls, their aria-setsize and aria-posinset attributes are set appropriately.

Back to top

Combo box example

Pope Tech’s web accessibility platform uses a combo box for our search. It’s an editable combo box with a list box pop-up. It uses list autocomplete, opens after a user types in characters, and selection happens when a user selects Enter.

Keyboard interactions example

This video demos the keyboard interactions in Pope Tech’s search combo box:

ARIA implemented example

Here’s how Pope Tech’s search combo box uses ARIA. Other CSS classes and divs are used to achieve the search, but this outlines what elements have different ARIA elements. Also, some of these states and properties are added when the list box triggers.

Pope Tech's search combo box that's expanded showing suggested options.

Combo box input ARIA

  • A form element wraps the search input and list box pop-up.
  • The search input uses a visible HTML label.
  • Within the form element is a div element that has:
    • role="combobox"
    • aria-haspopup="listbox"
    • aria-expanded="true" (state switches to false when list box is closed)
  • Within that div element is the input element that has:
    • aria-autocomplete="list"
    • aria-controls with the id of the list box element it controls (added when list box is triggered)
    • aria-activedescendant which changes to match the id of the focused suggestion when the list box is open (added when a list box suggestion has focus)
<form role="search">
  <label for="search-control">Search</label>
  <div role="combobox" aria=haspopup="listbox" aria-expanded="false">
    <input aria-autocomplete="list" aria-controls="1234" aria-activedescendant="item_1" id="search-control">

...list box code...


List box pop-up ARIA

  • Within the form element is a div element that has:
    • role="listbox"
    • id used to reference aria-controls
  • Within that div are multiple divs for each suggested option. They have:
    • role="option"
    • id used to reference aria-activedescendant
<form role="search">
...combo box input code...

  <div role="listbox" id="1234">
    <div role="option" id="item_1"></div>
    <div role="option" id="item_2"></div>
    <div role="option" id="item_3"></div>


Try automated testing for free

Try out Pope Tech with our Free Plan – no credit card required.

Monthly accessibility insights

Sign up to get monthly accessibility content similar to this article. Unsubscribe at any time.

    Back to top