Open UIOpen UI GitHub

Select (Editor's Draft)

Overview

The <select> is a control that provides a list of options for the user to select from.

Use Cases

The <select> control is primarily leveraged to select an option for within a form. For example when your buying a shirt you may be provided with a <select> that has options for sizes that you then select the appropriate one for you.

Prior Art/Examples

<select> Properties

Attribute NameTypeDefault ValueDescription
autocompletestringoffAllows the developer to provide a hint on how to search the content within the <option>(s)
autofocusboolfalseIf set to true the input will have focus set on page load
disabledboolinherited from containing elementIf set to true the user will not be able to interact with the control
formstringthe form that contains the <select>Represents the form owner, via the form attribute being the same as the id of the <form>
labelsNodeListA NodeList containing the <label> elements associated with the <select> element
lengthint0The number of <option> elements in the <select> element
multipleboolfalseIf set to true this will allow more than one <option>
namestringnullRepresents the name of the control
optionsHTMLOptionsCollectionReturns a HTMLOptionsCollection of the <option> elements contained by the <select> element
requiredboolfalseA value must be provided for the control if set to true
selectedIndexint-1The index of the first or last selected <option> element, depending on the value of multiple
selectedOptionsHTMLCollectionAn HTMLCollection of the selected <option> elements
sizeint0If the <select> is shown with a scrollbar, this represents how many <option>s are visible.
typestring"select-one"Returns either "select-multiple" or "select-one"
validationMessagestring""Represents the message that describes the validation constraints that the control does not satisfy
validityValidityStateRepresents the current validity state of the control
value string""Returns the value property of the first selected <option> if there is one, otherwise an empty string
willValidatebooltrueA boolean that indicates whether the button is a candidate for constraint validation. It is false if any conditions bar it from constraint validation.

<select> Methods

NameDescription
addAdds an <option> to the <select>'s collection of <option> elements
checkValidityChecks whether the element violates any of its validity constraints. If so, fires invalid and returns false
itemReturns the <option> at the specified index in the <select>'s <option> collection
namedItemReturns the <option> in the <select>'s <option> collection with the specified name
removeRemoves the <option> at the specified index in the <select>'s <option> collection
reportValidityIf the <select> violates any of its validity constraints, shows a visual indicator to the user, fires invalid, and returns false
setCustomValiditySets the custom validity message of the <select> to the specified string, or clears any custom validity error if passed an empty string

<optgroup> Properties

Property NameTypeDefault ValueDescription
disabledboolinherited from containing elementIf set to true the user will not be able to interact with any of the <options>(s) in the group
labelstringThe name of the group of <option>s. Required if element is used.

<option> Properties

Property NameTypeDefault ValueDescription
defaultSelectedboolfalseThe initial value of the selected attribute
disabledboolinherited from containing elementIf set to true the user will not be able to interact with the <option>
formHTMLFormElementReturns the form element that the <option> is associated with, the association is inherited from the <select>
indexlongThe position of the <option> in the list of options it belongs to, in tree order
labelstringReflects the value of the value attribute if it exists; else reflects Node.textContent
selected boolfalseIf set to true then the <option> is selected
textstringContains the text content of the element
valuestringReflects the value of the value attribute if it exists; else reflects Node.textContent

Anatomy

Diagram

Currently selected value

Structure

  • <select> - The root element that contains the button and listbox [required]
  • <button> - The button element that contains the selected value and triggers the visibility of the listbox [required]
  • <listbox> - The wrapper that contains the <option>(s) and <optgroup>(s) [required]
  • <optgroup> - Groups <options> together with a label [optional]
  • <option> - Can have one or more and represents the potential values that can be chosen by the user [required]

Content not allowed within the anatomy

The following interactive elements are NOT permitted within a <select> or its children:

  • button (outside of the pre-defined one)
  • datalist
  • input (all types)
  • meter
  • progress
  • select
  • textarea
  • anchor
  • iframe
  • object

Should <a> and <output> be included?

Should this apply to the entire anatomy or solely the <option> and <optgroup> element

Events

select

EventBehaviorImpacts
changeUpdates the textContent property of the selected-value slot with the value property text contenttextContent prop

part button

EventBehaviorImpacts
clickToggles the open state of the <select>open state
clickToggles aria-expanded attribute of the buttonaria-expanded attr
keydown(space)Toggles the open state of the <select>open state
keydown(space)Toggles aria-expanded attribute of the buttonaria-expanded attr
keydown(enter)Toggles the open state of the <select>open state
keydown(enter)Toggles aria-expanded of the button partaria-expanded attr

part listbox

EventBehaviorImpacts
keydown(down key)Moves focus to the next <option> in the listboxfocus
keydown(up key)Moves focus to the previous <option> in the listboxfocus
keydown(enter)Changes the selected state of the current <option> and updates the <select> value propertyselected prop
value prop
keydown(space)Changes the selected state of the current <option> and updates the <select> value propertyselected prop
value prop
keydown(enter)If the <select> does not have the multiple attribute then toggle the state of open of the <select>open state
keydown(enter)If the <select> does not have the multiple attribute then toggle the aria-expanded attribute of the buttonaria-expanded attr
keydown(space)If the <select> does not have the multiple attribute then toggle the state of open of the <select>open state
keydown(space)If the <select> does not have the multiple attribute then toggle the aria-expanded attribute of the buttonaria-expanded attr
keydown(escape)Toggles the open state of the <select>open state
keydown(any single character that no other listbox event listens to)Run the typeahead steps given <select> and event.keyfocus

part option

EventBehaviorImpacts
clickChanges the selected state of the current <option> and updates the <select> value propertyselected prop
value prop
clickIf the <select> does not have the multiple attribute then toggle the state of open of the <select>open state
clickIf the <select> does not have the multiple attribute then toggle the aria-expanded attribute of the buttonaria-expanded attr

Behavior

States

open

This state is applied to the <select> when the listbox is visible to the user.

required

An <option> from the <select> must be selected when the required attribute is set to true

valid

The <select> meets all its validation constraints, and is therefore considered to be valid.

invalid

The <select> does not meet its validation constraints, and is therefore considered to be invalid.

Interaction & transition of states

Default State

  • Show the currently selected <option> or the first <option>
  • When the user invokes the button by:
    • a pointerup or click event is fired
    • the user presses the space or enter key
  • The state of the <select> is set to open

Open State

  • The currently selected <option>, or the first if one isn't selected, should be visible within the listbox. This may require moving the list to accomodate listbox positioning and available space.
  • The user can dismiss the listbox and remove the state of open from the <select> in either of the following manners:
    • Triggering any of the listbox's light dismiss behaviors
    • Selecting one, or more (if multiple is true), options by clicking or hitting the enter or space key

Light dismiss

The listbox part has "light dismiss", behavior, defined as being dismissed (removing the open state of the <select>, in this case) by either of the following things:

  • The user presses the escape key.
  • A focus change occurs (because of either user interaction or script), where the focus target is outside of the subtree of the listbox. This includes the case where the user invokes a non-focusable element, which causes focus to switch to the <body>.
    • There is one exception to this: if a user invokes a non-focusable element in the subtree of the listbox, focus still moves to the <body>, but "light dismiss" does not occur.

Typeahead

The typeahead steps given a <select> and a typed character are as follows:

  1. Let start new search be false.
  2. If longer than the typeahead search timeout has elapsed since the previous invocation of the typeahead steps for listbox, then set start new search to true and set buffer to an empty string.
  3. Let buffer be <select>'s typeahead buffer
  4. Append typed character to buffer.
  5. Let options be the <select>'s list of options.
  6. If start new search is true, then let starting option be the option after the currently focused option (this is the first option if the currently focused option is the last option). Otherwise let starting option be the currently focused option.

    The point is that if we're in the middle of a search, we should keep trying to match on the currently selected <option>. If this is a new search, we should start searching at the <option> after the currently selected <option>. If the user wanted the current <option>, then presumably they wouldn't still be typing search text.

  7. Let newly focused option be the result of finding the first matching option given buffer, options, and starting option.
  8. If newly focused option is not null, move focus to newly focused option.

To find the first matching option given a character buffer buffer and a list of options options, and a starting option, run these steps:

  1. For each option in options, starting with starting option, proceeding until the last option, then starting from the first option and proceeding to the option before starting option:
    1. Let match text be option.label with whitespace at the beginning and end removed (whitespace characters between non-whitespace characters are not removed).
    2. If buffer is a case-insensitive prefix of match text, then return option.
  2. Return null.

The typeahead buffer of a <select>

A buffer containing the characters typed by the user for typeahead. Initially an empty string.

Typeahead search timeout

This is the maximum time that may elapse between keystrokes without the typeahead search being reset. The value is left to implementations to determine. Typically it will be somewhere around 0.5-1s.

Listbox positioning

When the <select> is in its open state the listbox should

  • Be positioned allow for the greatest visibility of the listbox as possible.
  • Let currentBox equal the button's getBoundingClientRect
  • Let viewportHeight equal document.innerWidth
  • Let availableTop equal viewportHeight - currentBox.top
  • Let availableBottom equal viewportHeight - currentBox.bottom
  • If availableTop is greater than availableBottom:
  • else

Some frameworks allow a forced directionality with the default being an auto positioning as described above.

Use with Assistive Technology

Implements the combobox role per the HTML AAM spec.

Security

Avoiding UI spoofing

If a listbox is rendered outside of the viewport, then it is highly recommended to limit control over the possible adjustments that an author can make. This is due to the developer being able to overlay their content with the application's UI, of which the user trusts and can result in clickjacking due to UI spoofing. If the application enables the author to have complete control over its appearance, the implementor MUST render the listbox within the viewport.

This also MUST apply to embedded content, such as an <iframe> as it may try to mimick the appearance of the site it is being embedded on.

Open Questions

  • Provide arbitrary HTML into <option> elements
    • What is the value of an option with complex content? [Issue 69]
    • How does focus work with focusable children within the control?
    • How does form validation work?

Resources


Acknowledgements

Some method and attribute definitions were sourced from the MDN definitions