|
| 1 | +The `@angular/cdk/listbox` module provides directives to help create custom listbox interactions |
| 2 | +based on the [WAI ARIA listbox pattern][aria]. |
| 3 | + |
| 4 | +By using `@angular/cdk/listbox` you get all the expected behaviors for an accessible experience, |
| 5 | +including bidi layout support, keyboard interaction, and focus management. All directives apply |
| 6 | +their associated ARIA roles to their host element. |
| 7 | + |
| 8 | +### Supported ARIA Roles |
| 9 | + |
| 10 | +The directives in `@angular/cdk/listbox` set the appropriate roles on their host element. |
| 11 | + |
| 12 | +| Directive | ARIA Role | |
| 13 | +|------------|-----------| |
| 14 | +| cdkOption | option | |
| 15 | +| cdkListbox | listbox | |
| 16 | + |
| 17 | +### CSS Styles and Classes |
| 18 | + |
| 19 | +The `@angular/cdk/listbox` is designed to be highly customizable to your needs. It therefore does not |
| 20 | +make any assumptions about how elements should be styled. You are expected to apply any required |
| 21 | +CSS styles, but the directives do apply CSS classes to make it easier for you to add custom styles. |
| 22 | +The available CSS classes are listed below, by directive. |
| 23 | + |
| 24 | +| Directive | CSS Class | Applied... | |
| 25 | +|:---------------|--------------------|-------------------------| |
| 26 | +| cdkOption | .cdk-option | Always | |
| 27 | +| cdkOption | .cdk-option-active | If the option is active | |
| 28 | +| cdkListbox | .cdk-listbox | Always | |
| 29 | + |
| 30 | +In addition to CSS classes, these directives add aria attributes that can be targeted in CSS. |
| 31 | + |
| 32 | +| Directive | Attribute Selector | Applied... | |
| 33 | +|:-----------|----------------------------------|------------------------------------------| |
| 34 | +| cdkOption | \[aria-disabled="true"] | If the option is disabled | |
| 35 | +| cdkOption | \[aria-selected="true"] | If the option is selected | |
| 36 | +| cdkListbox | \[aria-disabled="true"] | If the listbox is selected | |
| 37 | +| cdkListbox | \[aria-multiselectable="true"] | If the listbox allows multiple selection | |
| 38 | +| cdkListbox | \[aria-orientation="horizontal"] | If the listbox is oriented horizontally | |
| 39 | +| cdkListbox | \[aria-orientation="vertical"] | If the listbox is oriented vertically | |
| 40 | + |
| 41 | +### Getting started |
| 42 | + |
| 43 | +Import the `CdkListboxModule` into the `NgModule` in which you want to create a listbox. You can |
| 44 | +then apply listbox directives to build your custom listbox. A typical listbox consists of the |
| 45 | +following directives: |
| 46 | + |
| 47 | +- `cdkListbox` - Added to the container element containing the options to be selected |
| 48 | +- `cdkOption` - Added to each selectable option in the listbox |
| 49 | + |
| 50 | +<!-- example({ |
| 51 | + "example": "cdk-listbox-overview", |
| 52 | + "file": "cdk-listbox-overview-example.html", |
| 53 | + "region": "listbox" |
| 54 | +}) --> |
| 55 | + |
| 56 | +### Option values |
| 57 | + |
| 58 | +Each option in a listbox is bound to the value it represents when selected, e.g. |
| 59 | +`<li cdkOption="red">Red</li>`. Within a single listbox, each option must have a unique value. If |
| 60 | +an option is not explicitly given a value, its value is considered to be `''` (empty string), e.g. |
| 61 | +`<li cdkOption>No color preference</li>`. |
| 62 | + |
| 63 | +<!-- example({ |
| 64 | + "example": "cdk-listbox-overview", |
| 65 | + "file": "cdk-listbox-overview-example.html", |
| 66 | + "region": "option" |
| 67 | +}) --> |
| 68 | + |
| 69 | +### Single vs multiple selection |
| 70 | + |
| 71 | +Listboxes only support a single selected option at a time by default, but adding |
| 72 | +`cdkListboxMultiple` will enable selecting more than one option. |
| 73 | + |
| 74 | +<!-- example({ |
| 75 | + "example": "cdk-listbox-multiple", |
| 76 | + "file": "cdk-listbox-multiple-example.html", |
| 77 | + "region": "listbox" |
| 78 | +}) --> |
| 79 | + |
| 80 | +### Listbox value |
| 81 | + |
| 82 | +The listbox's value is an array containing the values of the selected option(s). This is true even |
| 83 | +for the single selection listbox, whose value is an array containing a single element. The listbox's |
| 84 | +value can be bound using `[cdkListboxValue]` and `(cdkListboxValueChange)`. |
| 85 | + |
| 86 | +<!-- example({ |
| 87 | + "example": "cdk-listbox-value-binding", |
| 88 | + "file": "cdk-listbox-value-binding-example.html", |
| 89 | + "region": "listbox" |
| 90 | +}) --> |
| 91 | + |
| 92 | +Internally the listbox compares the listbox value against the individual option values using |
| 93 | +`Object.is` to determine which options should appear selected. If your option values are complex |
| 94 | +objects, you should provide a custom comparison function instead. This can be set via the |
| 95 | +`cdkListboxCompareWith` input on the listbox. |
| 96 | + |
| 97 | +<!-- example({ |
| 98 | + "example": "cdk-listbox-compare-with", |
| 99 | + "file": "cdk-listbox-compare-with-example.html", |
| 100 | + "region": "listbox" |
| 101 | +}) --> |
| 102 | + |
| 103 | +### Angular Forms support |
| 104 | + |
| 105 | +The CDK Listbox supports both template driven forms and reactive forms. |
| 106 | + |
| 107 | +<!-- example({ |
| 108 | + "example": "cdk-listbox-template-forms", |
| 109 | + "file": "cdk-listbox-template-forms-example.html", |
| 110 | + "region": "listbox" |
| 111 | +}) --> |
| 112 | + |
| 113 | +<!-- example({ |
| 114 | + "example": "cdk-listbox-reactive-forms", |
| 115 | + "file": "cdk-listbox-reactive-forms-example.html", |
| 116 | + "region": "listbox" |
| 117 | +}) --> |
| 118 | + |
| 119 | +#### Forms validation |
| 120 | + |
| 121 | +The CDK listbox integrates with Angular's form validation API and has the following built-in |
| 122 | +validation errors: |
| 123 | + |
| 124 | +- `cdkListboxUnexpectedOptionValues` - Raised when the bound value contains values that do not |
| 125 | + appear as option value in the listbox. The validation error contains a `values` property that |
| 126 | + lists the invalid values |
| 127 | +- `cdkListboxUnexpectedMultipleValues` - Raised when a single-selection listbox is bound to a value |
| 128 | + containing multiple selected options. |
| 129 | + |
| 130 | +<!-- example({ |
| 131 | + "example": "cdk-listbox-forms-validation", |
| 132 | + "file": "cdk-listbox-forms-validation-example.ts", |
| 133 | + "region": "errors" |
| 134 | +}) --> |
| 135 | + |
| 136 | +### Disabling options |
| 137 | + |
| 138 | +You can disable options for selection by setting `cdkOptionDisabled`. |
| 139 | +In addition, the entire listbox control can be disabled by setting `cdkListboxDisabled` on the |
| 140 | +listbox element. |
| 141 | + |
| 142 | +<!-- example({ |
| 143 | + "example": "cdk-listbox-disabled", |
| 144 | + "file": "cdk-listbox-disabled-example.html", |
| 145 | + "region": "listbox" |
| 146 | +}) --> |
| 147 | + |
| 148 | +### Accessibility |
| 149 | + |
| 150 | +The directives defined in `@angular/cdk/listbox` follow accessibility best practices as defined |
| 151 | +in the [ARIA spec][aria]. Keyboard interaction is supported as defined in the |
| 152 | +[ARIA listbox keyboard interaction spec][keyboard] _without_ the optional selection follows focus |
| 153 | +logic (TODO: should we make this an option?). |
| 154 | + |
| 155 | +#### Listbox label |
| 156 | + |
| 157 | +Always give the listbox a meaningful label for screen readers. If your listbox has a visual label, |
| 158 | +you can associate it with the listbox using `aria-labelledby`, otherwise you should provide a |
| 159 | +screen-reader-only label with `aria-label`. |
| 160 | + |
| 161 | +#### Roving tabindex vs active descendant |
| 162 | + |
| 163 | +By default, the CDK listbox uses the [roving tabindex][roving-tabindex] strategy to manage focus. |
| 164 | +If you prefer to use the [aria-activedescendant][activedescendant] strategy instead, set |
| 165 | +`useActiveDescendant=true` on the listbox. |
| 166 | + |
| 167 | +<!-- example({ |
| 168 | + "example": "cdk-listbox-activedescendant", |
| 169 | + "file": "cdk-listbox-activedescendant-example.html", |
| 170 | + "region": "listbox" |
| 171 | +}) --> |
| 172 | + |
| 173 | +#### Orientation |
| 174 | + |
| 175 | +Listboxes assume a vertical orientation by default, but can be customized by setting the |
| 176 | +`cdkListboxOrientation` input. Note that this only affects the keyboard navigation. You |
| 177 | +will still need to adjust your CSS styles to change the visual appearance. |
| 178 | + |
| 179 | +<!-- example({ |
| 180 | + "example": "cdk-listbox-horizontal", |
| 181 | + "file": "cdk-listbox-horizontal-example.html", |
| 182 | + "region": "listbox" |
| 183 | +}) --> |
| 184 | + |
| 185 | +#### Option typeahead |
| 186 | + |
| 187 | +The CDK listbox supports typeahead based on the option text. If the typeahead text for your options |
| 188 | +needs to be different than the display text (e.g. to exclude emoji), this can be accomplished by |
| 189 | +setting the `cdkOptionTypeaheadLabel` on the option. |
| 190 | + |
| 191 | +<!-- example({ |
| 192 | + "example": "cdk-listbox-custom-typeahead", |
| 193 | + "file": "cdk-listbox-custom-typeahead-example.html", |
| 194 | + "region": "listbox" |
| 195 | +}) --> |
| 196 | + |
| 197 | +#### Keyboard navigation options |
| 198 | + |
| 199 | +When using keyboard navigation to navigate through the options, the navigation wraps when attempting |
| 200 | +to navigate past the start or end of the options. To change this, set |
| 201 | +`cdkListboxNavigationWrapDisabled` on the listbox. |
| 202 | + |
| 203 | +Keyboard navigation skips disabled options by default. To change this set |
| 204 | +`cdkListboxNavigatesDisabledOptions` on the listbox. |
| 205 | + |
| 206 | +<!-- example({ |
| 207 | + "example": "cdk-listbox-custom-navigation", |
| 208 | + "file": "cdk-listbox-custom-navigation-example.html", |
| 209 | + "region": "listbox" |
| 210 | +}) --> |
| 211 | + |
| 212 | +<!-- links --> |
| 213 | + |
| 214 | +[aria]: https://www.w3.org/WAI/ARIA/apg/patterns/listbox/ 'WAI ARIA Listbox Pattern' |
| 215 | +[keyboard]: https://www.w3.org/WAI/ARIA/apg/patterns/listbox/#keyboard-interaction-11 'WAI ARIA Listbox Keyboard Interaction' |
| 216 | +[roving-tabindex]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex 'MDN Roving Tabindex Technique' |
| 217 | +[activedescendant]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#technique_2_aria-activedescendant 'MDN aria-activedescendant Technique' |
0 commit comments