diff --git a/src/demo-app/a11y/a11y-module.ts b/src/demo-app/a11y/a11y-module.ts index b27f2c0f89e6..9911341393ea 100644 --- a/src/demo-app/a11y/a11y-module.ts +++ b/src/demo-app/a11y/a11y-module.ts @@ -29,6 +29,7 @@ import { } from './dialog/dialog-a11y'; import {ExpansionPanelAccessibilityDemo} from './expansion/expansion-a11y'; import {GridListAccessibilityDemo} from './grid-list/grid-list-a11y'; +import {ListAccessibilityDemo} from './list/list-a11y'; import {RadioAccessibilityDemo} from './radio/radio-a11y'; import {ToolbarAccessibilityDemo} from './toolbar/toolbar-a11y'; import {DatepickerAccessibilityDemo} from './datepicker/datepicker-a11y'; @@ -93,6 +94,7 @@ export class AccessibilityRoutingModule {} GridListAccessibilityDemo, IconAccessibilityDemo, InputAccessibilityDemo, + ListAccessibilityDemo, MenuAccessibilityDemo, ProgressBarAccessibilityDemo, ProgressSpinnerAccessibilityDemo, diff --git a/src/demo-app/a11y/a11y.ts b/src/demo-app/a11y/a11y.ts index 3ac3cd80d39d..9db5dda65aa7 100644 --- a/src/demo-app/a11y/a11y.ts +++ b/src/demo-app/a11y/a11y.ts @@ -49,6 +49,7 @@ export class AccessibilityDemo implements OnDestroy { {name: 'Grid list', route: 'grid-list'}, {name: 'Icon', route: 'icon'}, {name: 'Input', route: 'input'}, + {name: 'List', route: 'list'}, {name: 'Menu', route: 'menu'}, {name: 'Progress bar', route: 'progress-bar'}, {name: 'Progress spinner', route: 'progress-spinner'}, diff --git a/src/demo-app/a11y/list/list-a11y.html b/src/demo-app/a11y/list/list-a11y.html new file mode 100644 index 000000000000..70eea8b8410b --- /dev/null +++ b/src/demo-app/a11y/list/list-a11y.html @@ -0,0 +1,66 @@ +
+
+

Seasoning

+

Showing a non-interactive list of seasonings.

+ + {{item}} + +
+ + +
+

Mailbox navigation

+

Showing a navigation list with links to google search

+ + + {{link.name}} + + +
+ +
+

Messages

+

+ Showing a list of messages, where each message item has sender's name, sender's avatar, + message subject, and content of the message. +

+ + + +

{{message.from}}

+

{{message.subject}}

+

{{message.message}}

+
+
+ +
+ +
+

Seasoning

+

Showing a non-interactive list of seasonings with dense style.

+ + {{item}} + +
+ +
+

Folders and notes for mailbox

+

Showing a list with two sections, "folders" and "notes".

+ +

Folders

+ + folder +

{{folder.name}}

+

{{folder.updated}}

+
+ +

Notes

+ + note +

{{note.name}}

+

{{note.updated}}

+
+
+
+
diff --git a/src/demo-app/a11y/list/list-a11y.scss b/src/demo-app/a11y/list/list-a11y.scss new file mode 100644 index 000000000000..1d270debe13d --- /dev/null +++ b/src/demo-app/a11y/list/list-a11y.scss @@ -0,0 +1,11 @@ +.demo-list { + .mat-list, .mat-nav-list { + border: 1px solid rgba(0, 0, 0, 0.12); + max-width: 350px; + margin: 20px 20px 0 0; + } + + .demo-secondary-text { + color: rgba(0, 0, 0, 0.54); + } +} diff --git a/src/demo-app/a11y/list/list-a11y.ts b/src/demo-app/a11y/list/list-a11y.ts new file mode 100644 index 000000000000..3a033d24cb58 --- /dev/null +++ b/src/demo-app/a11y/list/list-a11y.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component} from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'list-a11y', + templateUrl: 'list-a11y.html', + styleUrls: ['list-a11y.css'] +}) +export class ListAccessibilityDemo { + items: string[] = [ + 'Pepper', + 'Salt', + 'Paprika' + ]; + + messages = [ + { + from: 'Nancy', + subject: 'Brunch?', + message: 'Did you want to go on Sunday? I was thinking that might work.', + image: 'https://angular.io/generated/images/bios/julie-ralph.jpg' + }, + { + from: 'Mary', + subject: 'Summer BBQ', + message: 'Wish I could come, but I have some prior obligations.', + image: 'https://angular.io/generated/images/bios/juleskremer.jpg' + }, + { + from: 'Bobby', + subject: 'Oui oui', + message: 'Do you have Paris reservations for the 15th? I just booked!', + image: 'https://angular.io/generated/images/bios/jelbourn.jpg' + } + ]; + + links = [ + {name: 'Inbox'}, + {name: 'Outbox'}, + {name: 'Spam'}, + {name: 'Trash'} + + ]; + + folders = [ + {name: 'Imported', updated: 'Miles'}, + {name: 'Important', updated: 'Tina'}, + {name: 'Unread', updated: 'Jeremy'}, + ]; + + notes = [ + {name: 'Update screenshots', updated: 'Kara'}, + {name: 'Install new application', updated: 'Andrew'}, + ]; +} diff --git a/src/demo-app/a11y/routes.ts b/src/demo-app/a11y/routes.ts index 6d729336e2c5..8ce0372611af 100644 --- a/src/demo-app/a11y/routes.ts +++ b/src/demo-app/a11y/routes.ts @@ -22,6 +22,7 @@ import {ToolbarAccessibilityDemo} from './toolbar/toolbar-a11y'; import {DatepickerAccessibilityDemo} from './datepicker/datepicker-a11y'; import {IconAccessibilityDemo} from './icon/icon-a11y'; import {InputAccessibilityDemo} from './input/input-a11y'; +import {ListAccessibilityDemo} from './list/list-a11y'; import {MenuAccessibilityDemo} from './menu/menu-a11y'; import {ProgressBarAccessibilityDemo} from './progress-bar/progress-bar-a11y'; import {ProgressSpinnerAccessibilityDemo} from './progress-spinner/progress-spinner-a11y'; @@ -52,6 +53,7 @@ export const ACCESSIBILITY_DEMO_ROUTES: Routes = [ {path: 'grid-list', component: GridListAccessibilityDemo}, {path: 'icon', component: IconAccessibilityDemo}, {path: 'input', component: InputAccessibilityDemo}, + {path: 'list', component: ListAccessibilityDemo}, {path: 'menu', component: MenuAccessibilityDemo}, {path: 'progress-bar', component: ProgressBarAccessibilityDemo}, {path: 'progress-spinner', component: ProgressSpinnerAccessibilityDemo}, diff --git a/src/lib/list/list-module.ts b/src/lib/list/list-module.ts index dea04202fd89..d29e01c1b0e7 100644 --- a/src/lib/list/list-module.ts +++ b/src/lib/list/list-module.ts @@ -17,13 +17,12 @@ import { import { MatDividerCssMatStyler, MatList, + MatNavList, MatListAvatarCssMatStyler, - MatListCssMatStyler, MatListDivider, MatListIconCssMatStyler, MatListItem, MatListSubheaderCssMatStyler, - MatNavListCssMatStyler, } from './list'; import {MatListOption, MatSelectionList} from './selection-list'; @@ -32,14 +31,13 @@ import {MatListOption, MatSelectionList} from './selection-list'; imports: [MatLineModule, MatRippleModule, MatCommonModule, MatPseudoCheckboxModule, CommonModule], exports: [ MatList, + MatNavList, MatListItem, MatListDivider, MatListAvatarCssMatStyler, MatLineModule, MatCommonModule, MatListIconCssMatStyler, - MatListCssMatStyler, - MatNavListCssMatStyler, MatDividerCssMatStyler, MatListSubheaderCssMatStyler, MatPseudoCheckboxModule, @@ -48,12 +46,11 @@ import {MatListOption, MatSelectionList} from './selection-list'; ], declarations: [ MatList, + MatNavList, MatListItem, MatListDivider, MatListAvatarCssMatStyler, MatListIconCssMatStyler, - MatListCssMatStyler, - MatNavListCssMatStyler, MatDividerCssMatStyler, MatListSubheaderCssMatStyler, MatSelectionList, diff --git a/src/lib/list/list.html b/src/lib/list/list.html new file mode 100644 index 000000000000..9af43669be38 --- /dev/null +++ b/src/lib/list/list.html @@ -0,0 +1,2 @@ + + diff --git a/src/lib/list/list.md b/src/lib/list/list.md index b26595f5becf..43d5786bf6fc 100644 --- a/src/lib/list/list.md +++ b/src/lib/list/list.md @@ -150,3 +150,12 @@ To add a divider, use ``. ``` + +### Accessibility +By default, the list assumes that it will be used in a purely decorative fashion and thus sets no +roles, ARIA attributes, or keyboard shortcuts. This is equivalent to having a sequence of
+elements on the page. Any interactive content within the list should be given an appropriate +accessibility treatment based on the specific workflow of your application. + +If the list is used to present a list of non-interactive content items, then the list element should +be given `role="list"` and each list item should be given `role="listitem"`. diff --git a/src/lib/list/list.spec.ts b/src/lib/list/list.spec.ts index f2b60c500aef..b7644f7e247c 100644 --- a/src/lib/list/list.spec.ts +++ b/src/lib/list/list.spec.ts @@ -115,7 +115,7 @@ describe('MatList', () => { let list = fixture.debugElement.children[0]; let listItem = fixture.debugElement.children[0].query(By.css('mat-list-item')); - expect(list.nativeElement.getAttribute('role')).toBe('list'); + expect(list.nativeElement.getAttribute('role')).toBeNull(); expect(listItem.nativeElement.getAttribute('role')).toBe('listitem'); }); diff --git a/src/lib/list/list.ts b/src/lib/list/list.ts index 6cd9efcd0f9a..ab278121609d 100644 --- a/src/lib/list/list.ts +++ b/src/lib/list/list.ts @@ -44,37 +44,34 @@ export class MatListDivider {} /** A Material Design list component. */ @Component({ moduleId: module.id, - selector: 'mat-list, mat-nav-list', - exportAs: 'matList, matNavList', - host: {'role': 'list'}, - template: '', + selector: 'mat-nav-list', + exportAs: 'matNavList', + host: { + 'role': 'navigation', + 'class': 'mat-nav-list' + }, + templateUrl: 'list.html', styleUrls: ['list.css'], inputs: ['disableRipple'], encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MatList extends _MatListMixinBase implements CanDisableRipple {} +export class MatNavList extends _MatListMixinBase implements CanDisableRipple {} -/** - * Directive whose purpose is to add the mat- CSS styling to this selector. - * @docs-private - */ -@Directive({ +@Component({ + moduleId: module.id, selector: 'mat-list', - host: {'class': 'mat-list'} -}) -export class MatListCssMatStyler {} - -/** - * Directive whose purpose is to add the mat- CSS styling to this selector. - * @docs-private - */ -@Directive({ - selector: 'mat-nav-list', - host: {'class': 'mat-nav-list'} + exportAs: 'matList', + templateUrl: 'list.html', + host: {'class': 'mat-list'}, + styleUrls: ['list.css'], + inputs: ['disableRipple'], + encapsulation: ViewEncapsulation.None, + preserveWhitespaces: false, + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MatNavListCssMatStyler {} +export class MatList extends _MatListMixinBase implements CanDisableRipple {} /** * Directive whose purpose is to add the mat- CSS styling to this selector. @@ -150,10 +147,9 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn } constructor(private _element: ElementRef, - @Optional() private _list: MatList, - @Optional() navList: MatNavListCssMatStyler) { + @Optional() private _navList: MatNavList) { super(); - this._isNavList = !!navList; + this._isNavList = !!_navList; } ngAfterContentInit() { @@ -162,7 +158,7 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn /** Whether this list item should show a ripple effect when clicked. */ _isRippleDisabled() { - return !this._isNavList || this.disableRipple || this._list.disableRipple; + return !this._isNavList || this.disableRipple || this._navList.disableRipple; } _handleFocus() { diff --git a/src/material-examples/list-overview/list-overview-example.html b/src/material-examples/list-overview/list-overview-example.html index 4c59db7aa84e..9c416b76f0d3 100644 --- a/src/material-examples/list-overview/list-overview-example.html +++ b/src/material-examples/list-overview/list-overview-example.html @@ -1,4 +1,4 @@ - + Item 1 Item 2 Item 3