Skip to content

Commit d71fa44

Browse files
vogtnnmetulev
authored andcommitted
Updating accessibility to components (#126)
* updating accessibility to components * [contributing.md] updating documentation with accesibility guidelines * [several components] adding aria-labels for meaningful context * [contributing.md] adding examples to accessibility guidelines
1 parent d429148 commit d71fa44

File tree

7 files changed

+151
-20
lines changed

7 files changed

+151
-20
lines changed

CONTRIBUTING.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,56 @@ We encourage developers to follow the following guidance when submitting new fea
122122
1. Update the [documentation](https://github.com/microsoftgraph/microsoft-graph-docs/tree/master/concepts/toolkit) when necessary
123123
1. Follow the [accessibility guidance](https://developer.mozilla.org/en-US/docs/Web/Accessibility) for web development
124124

125+
126+
### Accessibility Guidelines
127+
128+
New features and components should folow the following accessibility implementation guidelines:
129+
130+
(for ease of use)
131+
1. Visit the following location: https://accessibilityinsights.io/en/
132+
2. Install the extension, and test
133+
134+
**required**:
135+
- [ ] `aria-label` | *string*: "Login Button", "Megan Bowen" | - meaningful text should have identifiable labels for screen readers
136+
137+
*example (mgt-login):*
138+
139+
```html
140+
<button
141+
class="popup-command"
142+
@click=${this.logout}
143+
aria-label="Sign Out">
144+
Sign Out
145+
</button>
146+
```
147+
148+
- [ ] `tab-index/focus` | *string*: "0", "-1" | - components that are interactive or display information should be **visibilly** navigatable by `tab` key control. Additional information in the aria label should be displayed when this feature is used.
149+
150+
*example (mgt-people):*
151+
152+
```html
153+
<mgt-person tabindex="0" ></mgt-person>
154+
```
155+
```css
156+
mgt-person:focus{
157+
border-color: blue;
158+
}
159+
```
160+
161+
- [ ] `alt` | *string*: "person icon" | - any `<img>` tag should contain `alt` text as well
162+
163+
*example (mgt-person):*
164+
165+
```html
166+
<img
167+
title=${this.personDetails.displayName}
168+
aria-label=${this.personDetails.displayName}
169+
alt=${this.personDetails.displayName}
170+
src=${this.personDetails.image as string}
171+
/>
172+
```
173+
174+
125175
<!-- ### Testing
126176
127177
Your changes should include tests to verify new functionality wherever possible.

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html>
2+
<html lang="en">
33
<head>
44
<meta charset="utf-8" />
55
<meta http-equiv="X-UA-Compatible" content="IE=edge" />

src/components/mgt-agenda/mgt-agenda.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export class MgtAgenda extends MgtTemplatedComponent {
200200
<div class="group">
201201
${this.renderTemplate('header', { header: header }, 'header-' + header) ||
202202
html`
203-
<div class="header">${header}</div>
203+
<div class="header" aria-label="${header}">${header}</div>
204204
`}
205205
${this.renderListOfEvents(grouped[header])}
206206
</div>
@@ -257,7 +257,7 @@ export class MgtAgenda extends MgtTemplatedComponent {
257257
return html`
258258
<div class="event">
259259
<div class="event-time-container">
260-
<div class="event-time">${this.getEventTimeString(event)}</div>
260+
<div class="event-time" aria-label="${this.getEventTimeString(event)}">${this.getEventTimeString(event)}</div>
261261
</div>
262262
<div class="event-details-container">
263263
<div class="event-subject">${event.subject}</div>
@@ -296,7 +296,7 @@ export class MgtAgenda extends MgtTemplatedComponent {
296296
stroke="black"
297297
/>
298298
</svg>
299-
<div class="event-location">${event.location.displayName}</div>
299+
<div class="event-location" aria-label="${event.location.displayName}">${event.location.displayName}</div>
300300
</div>
301301
`;
302302
}

src/components/mgt-login/mgt-login.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export class MgtLogin extends MgtBaseComponent {
188188

189189
return html`
190190
<div class="root">
191-
<button ?disabled="${this._loading}" class="login-button" @click=${this.onClick}>
191+
<button ?disabled="${this._loading}" class="login-button" @click=${this.onClick} role="button">
192192
${content}
193193
</button>
194194
${this.renderMenu()}
@@ -199,7 +199,7 @@ export class MgtLogin extends MgtBaseComponent {
199199
renderLogIn() {
200200
return html`
201201
<i class="login-icon ms-Icon ms-Icon--Contact"></i>
202-
<span>
202+
<span aria-label="Sign In">
203203
Sign In
204204
</span>
205205
`;
@@ -233,7 +233,7 @@ export class MgtLogin extends MgtBaseComponent {
233233
<div class="popup-commands">
234234
<ul>
235235
<li>
236-
<button class="popup-command" @click=${this.logout}>
236+
<button class="popup-command" @click=${this.logout} aria-label="Sign Out">
237237
Sign Out
238238
</button>
239239
</li>

src/components/mgt-people-picker/mgt-people-picker.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,16 @@ export class MgtPicker extends MgtTemplatedComponent {
125125
if (event.keyCode == 40 || event.keyCode == 38) {
126126
//keyCodes capture: down arrow (40) and up arrow (38)
127127
this.handleArrowSelection(event);
128-
event.preventDefault();
128+
if (this._userInput.length > 0) {
129+
event.preventDefault();
130+
}
129131
}
130132
if (event.code == 'Tab' || event.code == 'Enter') {
133+
if (this.people.length) {
134+
event.preventDefault();
135+
}
131136
this.addPerson(this.people[this.arrowSelectionCount], event);
132137
event.target.value = '';
133-
event.preventDefault();
134138
}
135139
}
136140

@@ -186,7 +190,6 @@ export class MgtPicker extends MgtTemplatedComponent {
186190
}
187191

188192
private async loadPersonSearch(name: string) {
189-
console.log('here');
190193
if (name.length) {
191194
name = name.toLowerCase();
192195
let provider = Providers.globalProvider;
@@ -251,7 +254,9 @@ export class MgtPicker extends MgtTemplatedComponent {
251254
private renderErrorMessage() {
252255
return html`
253256
<div class="error-message-parent">
254-
<div class="search-error-text">We didn't find any matches.</div>
257+
<div label="search-error-text" aria-label="We didn't find any matches." class="search-error-text">
258+
We didn't find any matches.
259+
</div>
255260
</div>
256261
`;
257262
}
@@ -293,14 +298,17 @@ export class MgtPicker extends MgtTemplatedComponent {
293298
`;
294299
}
295300
return html`
296-
<ul class="people-chosen-list">
301+
<div class="people-chosen-list">
297302
${peopleList}
298303
<div class="${inputClass}">
299304
<input
300305
id="people-picker-input"
301306
class="people-chosen-input"
302307
type="text"
303308
placeholder="Start typing a name"
309+
label="people-picker-input"
310+
aria-label="people-picker-input"
311+
role="input"
304312
.value="${this._userInput}"
305313
@keydown="${(e: KeyboardEvent & { target: HTMLInputElement }) => {
306314
this.onUserKeyDown(e);
@@ -310,7 +318,7 @@ export class MgtPicker extends MgtTemplatedComponent {
310318
}}"
311319
/>
312320
</div>
313-
</ul>
321+
</div>
314322
`;
315323
}
316324

@@ -355,15 +363,15 @@ export class MgtPicker extends MgtTemplatedComponent {
355363
if (people) {
356364
if (people.length == 0 && this._userInput.length > 0 && this.isLoading == false) {
357365
return html`
358-
<ul class="people-list">
366+
<div class="people-list">
359367
${this.renderErrorMessage()}
360-
</ul>
368+
</div>
361369
`;
362370
} else {
363371
return html`
364-
<ul class="people-list">
372+
<div class="people-list">
365373
${this.renderPersons(people)}
366-
</ul>
374+
</div>
367375
`;
368376
}
369377
}

src/components/mgt-person/mgt-person.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ export class MgtPerson extends MgtTemplatedComponent {
169169
<img
170170
class="user-avatar ${this.getImageRowSpanClass()} ${this.getImageSizeClass()}"
171171
title=${this.personDetails.displayName}
172+
aria-label=${this.personDetails.displayName}
173+
alt=${this.personDetails.displayName}
172174
src=${this.personDetails.image as string}
173175
/>
174176
`;
@@ -177,8 +179,9 @@ export class MgtPerson extends MgtTemplatedComponent {
177179
<div
178180
class="user-avatar initials ${this.getImageRowSpanClass()} ${this.getImageSizeClass()}"
179181
title=${this.personDetails.displayName}
182+
aria-label=${this.personDetails.displayName}
180183
>
181-
<span class="initials-text">
184+
<span class="initials-text" aria-label="${this.getInitials()}">
182185
${this.getInitials()}
183186
</span>
184187
</div>
@@ -202,12 +205,12 @@ export class MgtPerson extends MgtTemplatedComponent {
202205

203206
const nameView = this.showName
204207
? html`
205-
<div class="user-name">${this.personDetails.displayName}</div>
208+
<div class="user-name" aria-label="${this.personDetails.displayName}">${this.personDetails.displayName}</div>
206209
`
207210
: null;
208211
const emailView = this.showEmail
209212
? html`
210-
<div class="user-email">${this.personDetails.email}</div>
213+
<div class="user-email" aria-label="${this.personDetails.email}">${this.personDetails.email}</div>
211214
`
212215
: null;
213216

src/components/mgt-tasks/mgt-tasks.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,31 @@ export class MgtTasks extends MgtBaseComponent {
5757
return styles;
5858
}
5959

60+
/**
61+
* readOnly property, determines if tasks are un-editable
62+
* @type {boolean}
63+
*/
6064
@property({ attribute: 'read-only', type: Boolean })
6165
public readOnly: boolean = false;
6266

67+
/**
68+
* data-source property, determines which task source is loaded, either planner or todo
69+
* @type {string}
70+
*/
6371
@property({ attribute: 'data-source', type: String })
6472
public dataSource: 'planner' | 'todo' = 'planner';
6573

74+
/**
75+
* target-id property, allows developer to define location of task component
76+
* @type {string}
77+
*/
6678
@property({ attribute: 'target-id', type: String })
6779
public targetId: string = null;
80+
81+
/**
82+
* target-bucket-id property, allows developer to define specific bucket id
83+
* @type {string}
84+
*/
6885
@property({ attribute: 'target-bucket-id', type: String })
6986
public targetBucketId: string = null;
7087

@@ -76,23 +93,68 @@ export class MgtTasks extends MgtBaseComponent {
7693
@property({ attribute: 'hide-header', type: Boolean })
7794
public hideHeader: boolean = false;
7895

96+
/**
97+
* _showNewTask property, determines if tasks needs to show new task
98+
* @type {boolean}
99+
*/
79100
@property() private _showNewTask: boolean = false;
101+
/**
102+
* _newTaskBeingAdded property, determines that new task is currently being added
103+
* @type {boolean}
104+
*/
80105
@property() private _newTaskBeingAdded: boolean = false;
106+
107+
/**
108+
* _newTaskSelfAssigned property, determines if user assigned task to themselves
109+
* @type {boolean}
110+
*/
81111
@property() private _newTaskSelfAssigned: boolean = true;
112+
113+
/**
114+
* _newTaskName property, contains new user created task name
115+
* @type {string}
116+
*/
82117
@property() private _newTaskName: string = '';
118+
119+
/**
120+
* _newTaskDueDate property, contains user chosen date for new task due date
121+
* @type {string}
122+
*/
83123
@property() private _newTaskDueDate: string = '';
124+
125+
/**
126+
* _newTaskDresserId property, contains id for new user created task??
127+
* @type {string}
128+
*/
84129
@property() private _newTaskDresserId: string = '';
130+
/**
131+
* _showNewTask property, determines if tasks needs to render new task
132+
* @type {string}
133+
*/
85134
@property() private _newTaskDrawerId: string = '';
86135

87136
@property() private _dressers: IDresser[] = [];
88137
@property() private _drawers: IDrawer[] = [];
138+
139+
/**
140+
* _tasks property, contains all user tasks
141+
* @type {string}
142+
*/
89143
@property() private _tasks: ITask[] = [];
90144

91145
@property() private _currentTargetDresser: string = this.res.BASE_SELF_ASSIGNED;
92146
@property() private _currentSubTargetDresser: string = this.res.PLANS_SELF_ASSIGNED;
93147
@property() private _currentTargetDrawer: string = this.res.BUCKETS_SELF_ASSIGNED;
94148

149+
/**
150+
* _hiddenTasks property, used for filter if task has been deleted
151+
* @type {string[]}
152+
*/
95153
@property() private _hiddenTasks: string[] = [];
154+
/**
155+
* _loadingTasks property, determines if tasks are in loading state
156+
* @type {string[]}
157+
*/
96158
@property() private _loadingTasks: string[] = [];
97159

98160
@property() private _inTaskLoad: boolean = false;
@@ -499,6 +561,9 @@ export class MgtTasks extends MgtBaseComponent {
499561
type="text"
500562
placeholder="Task..."
501563
.value="${this._newTaskName}"
564+
label="new-taskName-input"
565+
aria-label="new-taskName-input"
566+
role="input"
502567
@input="${(e: Event & { target: HTMLInputElement }) => {
503568
this._newTaskName = e.target.value;
504569
}}"
@@ -576,6 +641,9 @@ export class MgtTasks extends MgtBaseComponent {
576641
${this.renderCalendarIcon()}
577642
<input
578643
type="date"
644+
label="new-taskDate-input"
645+
aria-label="new-taskDate-input"
646+
role="input"
579647
.value="${this._newTaskDueDate}"
580648
@change="${(e: Event & { target: HTMLInputElement }) => {
581649
this._newTaskDueDate = e.target.value;
@@ -593,6 +661,8 @@ export class MgtTasks extends MgtBaseComponent {
593661
<input
594662
class="SelfAssign"
595663
type="checkbox"
664+
label="self-assign-input"
665+
aria-label="self-assign-input"
596666
.checked="${this._newTaskSelfAssigned}"
597667
@change="${(e: Event & { target: HTMLInputElement }) => {
598668
this._newTaskSelfAssigned = e.target.checked;

0 commit comments

Comments
 (0)