Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit 13abb24

Browse files
feat(list): Update list to toggle tabindex of radio/checkbox (#3542)
1 parent e203aa4 commit 13abb24

File tree

3 files changed

+28
-19
lines changed

3 files changed

+28
-19
lines changed

packages/mdc-list/README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,12 @@ The MDCList JavaScript component implements the WAI-ARIA best practices for
268268
[Listbox](https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox). This includes overriding the default tab behavior
269269
within the list component. You should not add `tabindex` to any of the `li` elements in a list.
270270

271-
As the user navigates through the list, any `button` or `a` elements within the list will receive `tabindex="-1"`
272-
when the list item is not focused. When the list item receives focus, the child `button` and `a` elements will
273-
receive `tabIndex="0"`. This allows for the user to tab through list item elements and then tab to the
274-
first element after the list. The `Arrow`, `Home`, and `End` keys should be used for navigating internal list elements.
275-
If `singleSelection=true`, the list will allow the user to use the `Space` or `Enter` keys to select or deselect
276-
a list item. The MDCList will perform the following actions for each key press
271+
As the user navigates through the list, any `button`, `a`, `input[type="radio"]` and `input[type="checkbox"]` elements
272+
within the list will receive `tabindex="-1"` when the list item is not focused. When the list item receives focus, the
273+
aforementioned elements will receive `tabIndex="0"`. This allows for the user to tab through list item elements
274+
and then tab to the first element after the list. The `Arrow`, `Home`, and `End` keys should be used for navigating
275+
internal list elements. If `singleSelection=true`, the list will allow the user to use the `Space` or `Enter` keys to
276+
select or deselect a list item. The MDCList will perform the following actions for each key press
277277

278278
Key | Action
279279
--- | ---
@@ -300,8 +300,8 @@ The default component requires that every list item receives a `tabindex` value
300300
(`li` elements cannot receive focus at all without a `tabindex` value). Any element not already containing a
301301
`tabindex` attribute will receive `tabindex=-1`. The first list item should have `tabindex="0"` so that the
302302
user can find the first element using the `tab` key, but subsequent `tab` keys strokes will cause focus to
303-
skip over the entire list. If the list items contain sub-elements that are focusable (`button` or `a` elements),
304-
these should also receive `tabIndex="-1"`.
303+
skip over the entire list. If the list items contain sub-elements that are focusable (`button`, `a`,
304+
`input[type="radio]`, and `input[type="checkbox"]` elements), these should also receive `tabIndex="-1"`.
305305

306306
```html
307307
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
@@ -352,7 +352,7 @@ Method Signature | Description
352352
`addClassForElementIndex(index: Number, className: String) => void` | Adds the `className` class to the list item at `index`.
353353
`removeClassForElementIndex(index: Number, className: String) => void` | Removes the `className` class to the list item at `index`.
354354
`focusItemAtIndex(index: Number) => void` | Focuses the list item at the `index` value specified.
355-
`setTabIndexForListItemChildren(index: Number, value: Number) => void` | Sets the `tabindex` attribute to `value` for each child `button` and `a` element in the list item at the `index` specified.
355+
`setTabIndexForListItemChildren(index: Number, value: Number) => void` | Sets the `tabindex` attribute to `value` for each child button, anchor, radio button and checkbox element in the list item at the `index` specified.
356356
`followHref(element: Element) => void` | If the given element has an href, follows the link.
357357

358358
### `MDCListFoundation`
@@ -364,8 +364,8 @@ Method Signature | Description
364364
`setSingleSelection(value: Boolean) => void` | Sets the list to be a selection list. Enables the `enter` and `space` keys for selecting/deselecting a list item.
365365
`setSelectedIndex(index: Number) => void` | Toggles the `selected` state of the list item at index `index`.
366366
`setUseActivated(useActivated: boolean) => void` | Sets the selection logic to apply/remove the `mdc-list-item--activated` class.
367-
`handleFocusIn(evt: Event) => void` | Handles the changing of `tabindex` to `0` for all `button` and `a` elements when a list item receives focus.
368-
`handleFocusOut(evt: Event) => void` | Handles the changing of `tabindex` to `-1` for all `button` and `a` elements when a list item loses focus.
367+
`handleFocusIn(evt: Event) => void` | Handles the changing of `tabindex` to `0` for all button, anchor, radio, and checkbox elements when a list item receives focus.
368+
`handleFocusOut(evt: Event) => void` | Handles the changing of `tabindex` to `-1` for all button, anchor, radio and checkbox elements when a list item loses focus.
369369
`handleKeydown(evt: Event) => void` | Handles determining if a focus action should occur when a key event is triggered.
370370
`handleClick(evt: Event) => void` | Handles toggling the selected/deselected state for a list item when clicked. This method is only used by the single selection list.
371371
`focusNextElement(index: Number) => void` | Handles focusing the next element using the current `index`.

packages/mdc-list/constants.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ const strings = {
3434
ARIA_ORIENTATION: 'aria-orientation',
3535
ARIA_ORIENTATION_HORIZONTAL: 'horizontal',
3636
ARIA_SELECTED: 'aria-selected',
37-
FOCUSABLE_CHILD_ELEMENTS: `.${cssClasses.LIST_ITEM_CLASS} button:not(:disabled), .${cssClasses.LIST_ITEM_CLASS} a`,
37+
FOCUSABLE_CHILD_ELEMENTS: `.${cssClasses.LIST_ITEM_CLASS} button:not(:disabled), .${cssClasses.LIST_ITEM_CLASS} a,
38+
.${cssClasses.LIST_ITEM_CLASS} input[type="radio"]:not(:disabled),
39+
.${cssClasses.LIST_ITEM_CLASS} input[type="checkbox"]:not(:disabled)`,
3840
ENABLED_ITEMS_SELECTOR: '.mdc-list-item:not(.mdc-list-item--disabled)',
3941
};
4042

test/unit/mdc-list/mdc-list.test.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ function getFixture() {
3535
Fruit
3636
<button>one</button>
3737
</li>
38+
<li class="mdc-list-item">
39+
Potato
40+
<a href="http://www.google.com">Link</a>
41+
</li>
3842
<li class="mdc-list-item">
3943
Pasta
40-
<button>two</button>
44+
<input type="checkbox"/>
4145
</li>
4246
<li class="mdc-list-item">
4347
Pizza
48+
<input type="radio"/>
4449
</li>
4550
</ul>
4651
`;
@@ -216,15 +221,17 @@ test('adapter#focusItemAtIndex focuses the list item at the index specified', ()
216221
document.body.removeChild(root);
217222
});
218223

219-
test('adapter#setTabIndexForListItemChildren sets the child button/a elements of index', () => {
224+
test('adapter#setTabIndexForListItemChildren sets the child button/a/radio/checkbox elements of index', () => {
220225
const {root, component} = setupTest();
221226
document.body.appendChild(root);
222-
const listItemIndex = 1;
223-
const listItem = root.querySelectorAll('.mdc-list-item')[listItemIndex];
224-
component.getDefaultFoundation().adapter_.setTabIndexForListItemChildren(listItemIndex, 0);
227+
const listItems = root.querySelectorAll('.mdc-list-item');
228+
229+
for (let index = 0; index < listItems.length; index++) {
230+
assert.equal(0, listItems[index].querySelectorAll('[tabindex="0"]').length);
231+
component.getDefaultFoundation().adapter_.setTabIndexForListItemChildren(index, 0);
232+
assert.equal(1, listItems[index].querySelectorAll('[tabindex="0"]').length);
233+
}
225234

226-
assert.equal(1, root.querySelectorAll('button[tabindex="0"]').length);
227-
assert.equal(listItem, root.querySelectorAll('button[tabindex="0"]')[0].parentElement);
228235
document.body.removeChild(root);
229236
});
230237

0 commit comments

Comments
 (0)