Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(list): Update ARIA attributes for radio/checkbox based list #4055

Merged
merged 24 commits into from
Nov 28, 2018
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d585757
fix(list): Auto update aria attributes based on check status
abhiomkar Nov 2, 2018
3aa9b8d
fix(list): Aria attributes to screenshot pages
abhiomkar Nov 5, 2018
db41f26
fix(list): update aria attributes based on list type
abhiomkar Nov 5, 2018
25bacc1
fix(list): Updated README
abhiomkar Nov 5, 2018
88ed948
fix(list): Updated to screenshot head > title
abhiomkar Nov 5, 2018
5a4892a
fix(list): Fix lint
abhiomkar Nov 5, 2018
5ce1753
fix(list): Updated readme to add radio, checkbox sections
abhiomkar Nov 5, 2018
b8c818c
fix(list): Update aria for only interactive lists
abhiomkar Nov 7, 2018
9d5223d
fix(list): resolve review comments.
abhiomkar Nov 9, 2018
ff65398
fix(list): Abstracted updating aria, classnames into private method f…
abhiomkar Nov 21, 2018
9ebc900
fix(list): Update code comments for preselected
abhiomkar Nov 21, 2018
0d7091e
fix(list): Updated list unit tests
abhiomkar Nov 27, 2018
73bed5a
fix(list): Updated list README
abhiomkar Nov 27, 2018
ad385e8
fix(list): Code comment
abhiomkar Nov 27, 2018
6228ab8
fix(list): fix auto toggle on label click
abhiomkar Nov 27, 2018
cb22dc9
fix(list): Review comments fix
abhiomkar Nov 28, 2018
3874baf
fix(list): Improved list foundation test coverage - 100%
abhiomkar Nov 28, 2018
da25244
fix(list): Test coverage 99.17% => 100%
abhiomkar Nov 28, 2018
5f48c2e
fix(list): Additional test for radio aria attribute change
abhiomkar Nov 28, 2018
509dbf6
fix(list): README change about tabindex
abhiomkar Nov 28, 2018
d8b4961
Merge remote-tracking branch 'origin/master' into fix/list_checkbox_aria
abhiomkar Nov 28, 2018
45f2f7d
fix(list): Updated README about checkbox role=group
abhiomkar Nov 28, 2018
57bc9f7
fix(list): trigger CBT
abhiomkar Nov 28, 2018
b4554a6
fix(list): Updated golden screenshots
abhiomkar Nov 28, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 160 additions & 26 deletions packages/mdc-list/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ npm install @material/list
### HTML Structure

```html
<ul class="mdc-list" aria-orientation="vertical">
abhiomkar marked this conversation as resolved.
Show resolved Hide resolved
<li class="mdc-list-item">
<ul class="mdc-list">
<li class="mdc-list-item" tabindex="0">
<span class="mdc-list-item__text">Single-line item</span>
</li>
<li class="mdc-list-item">
Expand All @@ -61,8 +61,8 @@ in the double line list style as defined by
[the spec](https://material.io/design/components/lists.html#specs) (see "Double line").

```html
<ul class="mdc-list mdc-list--two-line" aria-orientation="vertical">
<li class="mdc-list-item">
<ul class="mdc-list mdc-list--two-line">
<li class="mdc-list-item" tabindex="0">
<span class="mdc-list-item__text">
<span class="mdc-list-item__primary-text">First-line text</span>
<span class="mdc-list-item__secondary-text">Second-line text</span>
Expand Down Expand Up @@ -92,8 +92,8 @@ Multiple related lists can be grouped together using the `mdc-list-group` class
```html
<div class="mdc-list-group">
<h3 class="mdc-list-group__subheader">List 1</h3>
<ul class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item">
<ul class="mdc-list">
<li class="mdc-list-item" tabindex="0">
<span class="mdc-list-item__text">line item</span>
</li>
<li class="mdc-list-item">
Expand All @@ -104,7 +104,7 @@ Multiple related lists can be grouped together using the `mdc-list-group` class
</li>
</ul>
<h3 class="mdc-list-group__subheader">List 2</h3>
<ul class="mdc-list" aria-orientation="vertical">
<ul class="mdc-list">
<li class="mdc-list-item">
<span class="mdc-list-item__text">line item</span>
</li>
Expand All @@ -123,8 +123,8 @@ Multiple related lists can be grouped together using the `mdc-list-group` class
MDC List contains an `mdc-list-divider` class which can be used as full-width or inset subdivisions either within lists themselves, or standalone between related groups of content.

```html
<ul class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item">
<ul class="mdc-list">
<li class="mdc-list-item" tabindex="0">
<span class="mdc-list-item__text">Item 1 - Division 1</span>
</li>
<li class="mdc-list-item">
Expand All @@ -145,16 +145,16 @@ MDC List contains an `mdc-list-divider` class which can be used as full-width or
OR

```html
<ul class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item">
<ul class="mdc-list">
<li class="mdc-list-item" tabindex="0">
<span class="mdc-list-item__text">Item 1 - List 1</span>
</li>
<li class="mdc-list-item">
<span class="mdc-list-item__text">Item 2 - List 1</span>
</li>
</ul>
<hr class="mdc-list-divider">
<ul class="mdc-list" aria-orientation="vertical">
<ul class="mdc-list">
<li class="mdc-list-item">
<span class="mdc-list-item__text">Item 1 - List 2</span>
</li>
Expand All @@ -170,14 +170,14 @@ MDC List can handle selecting/deselecting list elements based on click or keyboa
single list item to become selected and any other previous selected element to become deselected.

```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item" tabindex="0">
<ul id="my-list" class="mdc-list" role="listbox">
<li class="mdc-list-item" role="option" tabindex="0">
<span class="mdc-list-item__text">Single-line item</span>
</li>
<li class="mdc-list-item">
<li class="mdc-list-item" role="option">
<span class="mdc-list-item__text">Single-line item</span>
</li>
<li class="mdc-list-item">
<li class="mdc-list-item" role="option">
<span class="mdc-list-item__text">Single-line item</span>
</li>
</ul>
Expand All @@ -196,14 +196,14 @@ the `mdc-list-item--selected` or `mdc-list-item--activated` class and `aria-sele
creating the list.

```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item">
<ul id="my-list" class="mdc-list" role="listbox">
<li class="mdc-list-item" role="option" aria-selected="false">
<span class="mdc-list-item__text">Single-line item</span>
</li>
<li class="mdc-list-item mdc-list-item--selected" aria-selected="true" tabindex="0">
<li class="mdc-list-item mdc-list-item--selected" role="option" aria-selected="true" tabindex="0">
<span class="mdc-list-item__text">Single-line item</span>
</li>
<li class="mdc-list-item">
<li class="mdc-list-item" role="option" aria-selected="false">
<span class="mdc-list-item__text">Single-line item</span>
</li>
</ul>
Expand All @@ -215,6 +215,131 @@ var list = new mdc.list.MDCList(listEle);
list.singleSelection = true;
```

### List with radio group

When rendering list radio group with pre-selected radio button the selected list item should contain `aria-checked` set to `true` and the native radio input element contains `checked` attribute, all other list items should have `aria-checked` set to `false`. The list root contains `role="radiogroup"` whereas each list item within radio group contains `role="radio"`.

```html
<ul class="mdc-list" role="radiogroup">
<li class="mdc-list-item" role="radio" aria-checked="false">
<span class="mdc-list-item__graphic">
<div class="mdc-radio">
<input class="mdc-radio__native-control"
type="radio"
id="demo-list-radio-item-1"
name="demo-list-radio-item-group"
value="1">
<div class="mdc-radio__background">
<div class="mdc-radio__outer-circle"></div>
<div class="mdc-radio__inner-circle"></div>
</div>
</div>
</span>
<label class="mdc-list-item__text" for="demo-list-radio-item-1">Option 1</label>
</li>
<li class="mdc-list-item" role="radio" aria-checked="true" tabindex="0">
<span class="mdc-list-item__graphic">
<div class="mdc-radio">
<input class="mdc-radio__native-control"
type="radio"
id="demo-list-radio-item-2"
name="demo-list-radio-item-group"
value="2"
checked>
<div class="mdc-radio__background">
<div class="mdc-radio__outer-circle"></div>
<div class="mdc-radio__inner-circle"></div>
</div>
</div>
</span>
<label class="mdc-list-item__text" for="demo-list-radio-item-2">Option 2</label>
</li>
<li class="mdc-list-item" role="radio" aria-checked="false">
<span class="mdc-list-item__graphic">
<div class="mdc-radio">
<input class="mdc-radio__native-control"
type="radio"
id="demo-list-radio-item-3"
name="demo-list-radio-item-group"
value="3">
<div class="mdc-radio__background">
<div class="mdc-radio__outer-circle"></div>
<div class="mdc-radio__inner-circle"></div>
</div>
</div>
</span>
<label class="mdc-list-item__text" for="demo-list-radio-item-3">Option 3</label>
</li>
</ul>
```

### List with checkbox items

When rendering list with checkbox items all pre-selected list items should contain `aria-checked` set to `true` and the native checkbox input element should contain `checked` attribute, all other list items should have `aria-checked` set to `false`. Each list item in checkbox list contains `role="checkbox"` attribute.
abhiomkar marked this conversation as resolved.
Show resolved Hide resolved

```html
<ul class="mdc-list">
<li class="mdc-list-item" role="checkbox" aria-checked="false">
<span class="mdc-list-item__graphic">
<div class="mdc-checkbox">
<input type="checkbox"
class="mdc-checkbox__native-control"
id="demo-list-checkbox-item-1" />
<div class="mdc-checkbox__background">
<svg class="mdc-checkbox__checkmark"
viewBox="0 0 24 24">
<path class="mdc-checkbox__checkmark-path"
fill="none"
d="M1.73,12.91 8.1,19.28 22.79,4.59"/>
</svg>
<div class="mdc-checkbox__mixedmark"></div>
</div>
</div>
</span>
<label class="mdc-list-item__text" for="demo-list-checkbox-item-1">Option 1</label>
</li>
<li class="mdc-list-item" role="checkbox" aria-checked="true" tabindex="0">
<span class="mdc-list-item__graphic">
<div class="mdc-checkbox">
<input type="checkbox"
class="mdc-checkbox__native-control"
id="demo-list-checkbox-item-2"
checked />
<div class="mdc-checkbox__background">
<svg class="mdc-checkbox__checkmark"
viewBox="0 0 24 24">
<path class="mdc-checkbox__checkmark-path"
fill="none"
d="M1.73,12.91 8.1,19.28 22.79,4.59"/>
</svg>
<div class="mdc-checkbox__mixedmark"></div>
</div>
</div>
</span>
<label class="mdc-list-item__text" for="demo-list-checkbox-item-2">Option 2</label>
</li>
<li class="mdc-list-item" role="checkbox" aria-checked="false">
<span class="mdc-list-item__graphic">
<div class="mdc-checkbox">
<input type="checkbox"
class="mdc-checkbox__native-control"
id="demo-list-checkbox-item-3" />
<div class="mdc-checkbox__background">
<svg class="mdc-checkbox__checkmark"
viewBox="0 0 24 24">
<path class="mdc-checkbox__checkmark-path"
fill="none"
d="M1.73,12.91 8.1,19.28 22.79,4.59"/>
</svg>
<div class="mdc-checkbox__mixedmark"></div>
</div>
</div>
</span>
<label class="mdc-list-item__text" for="demo-list-checkbox-item-3">Option 3</label>
</li>
</ul>
```

## Style Customization

### CSS Classes
Expand Down Expand Up @@ -266,15 +391,21 @@ Mixin | Description

The MDCList JavaScript component implements the WAI-ARIA best practices for
[Listbox](https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox). This includes overriding the default tab behavior
within the list component. You should not add `tabindex` to any of the `li` elements in a list.
within the list component.

The `tabindex` should be set to `0` for first list item element or selected list item element, remaining list item elements should not have `tabindex` set to `true`.
abhiomkar marked this conversation as resolved.
Show resolved Hide resolved

Use `role="listbox"` only for single selection list, without this role the `ul` element is implicitely `role="list"`.
Do not use `aria-orientation` attribute for standard list (i.e., `role="list"`), use component's `vertical` property to set the orientation
to vertical.

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

Key | Action
--- | ---
Expand Down Expand Up @@ -305,7 +436,7 @@ skip over the entire list. If the list items contain sub-elements that are focus
these should also receive `tabIndex="-1"`.

```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<ul id="my-list" class="mdc-list">
<li class="mdc-list-item" tabindex="0">
<span class="mdc-list-item__text">Single-line item</span>
<button tabindex="-1"></button>
Expand All @@ -328,7 +459,7 @@ to `-1`. The foundation method `setSelectedIndex()` should be called with the in
after the foundation is instantiated.

```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<ul id="my-list" class="mdc-list">
<li class="mdc-list-item" tabindex="-1">
<span class="mdc-list-item__text">Single-line item</span>
<button tabindex="-1"></button>
Expand All @@ -355,7 +486,10 @@ Method Signature | Description
`focusItemAtIndex(index: Number) => void` | Focuses the list item at the `index` value specified.
`setTabIndexForListItemChildren(index: Number, value: Number) => void` | Sets the `tabindex` attribute to `value` for each child button or anchor element in the list item at the `index` specified.
`followHref(element: Element) => void` | If the given element has an href, follows the link.
`toggleCheckbox(index: number) => boolean` | Toggles a checkbox and radio button in the list item and returns true/false if one was found.
`hasRadioAtIndex(index: number) => boolean` | Returns true if radio button is present at given list item index.
`hasCheckboxAtIndex(index: number) => boolean` | Returns true if checkbox is present at given list item index.
`isCheckboxCheckedAtIndex(index: number) => boolean` | Returns true if checkbox inside a list item is checked.
`setCheckedCheckboxOrRadioAtIndex(index: number, isChecked: boolean) => void` | Sets the checked status of checkbox or radio at given list item index.

### `MDCListFoundation`

Expand Down
24 changes: 21 additions & 3 deletions packages/mdc-list/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,29 @@ class MDCListAdapter {
followHref(ele) {}

/**
* Toggles the checkbox or radio button within a list item.
* @param {number} index
* @return {boolean} true if a radio button or checkbox was present.
* @return {boolean} Returns true if radio button is present at given list item index.
*/
toggleCheckbox(index) {}
hasRadioAtIndex(index) {}

/**
* @param {number} index
* @return {boolean} Returns true if checkbox is present at given list item index.
*/
hasCheckboxAtIndex(index) {}

/**
* @param {number} index
* @return {boolean} Returns true if checkbox inside a list item is checked.
*/
isCheckboxCheckedAtIndex(index) {}

/**
* Sets the checked status of checkbox or radio at given list item index.
* @param {number} index
* @param {boolean} isChecked
*/
setCheckedCheckboxOrRadioAtIndex(index, isChecked) {}
}

export default MDCListAdapter;
4 changes: 4 additions & 0 deletions packages/mdc-list/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ const strings = {
ARIA_ORIENTATION: 'aria-orientation',
ARIA_ORIENTATION_HORIZONTAL: 'horizontal',
ARIA_SELECTED: 'aria-selected',
ARIA_CHECKED: 'aria-checked',
ARIA_CHECKED_RADIO_SELECTOR: '[role="radio"][aria-checked="true"]',
RADIO_SELECTOR: 'input[type="radio"]:not(:disabled)',
CHECKBOX_SELECTOR: 'input[type="checkbox"]:not(:disabled)',
CHECKBOX_RADIO_SELECTOR: 'input[type="checkbox"]:not(:disabled), input[type="radio"]:not(:disabled)',
CHILD_ELEMENTS_TO_TOGGLE_TABINDEX: `.${cssClasses.LIST_ITEM_CLASS} button:not(:disabled),
.${cssClasses.LIST_ITEM_CLASS} a`,
Expand Down
Loading