Skip to content

Commit af34d15

Browse files
gavinbarronmusaleMnickii
authored
fix: keyboard navigation of login account list (#2289)
uses a basic list and allows keyboard navigation to provide proper focus highlighting --------- Co-authored-by: Musale Martin <[email protected]> Co-authored-by: Nickii Miaro <[email protected]>
1 parent e7efa21 commit af34d15

File tree

3 files changed

+74
-27
lines changed

3 files changed

+74
-27
lines changed

index.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@
3030
</head>
3131

3232
<body>
33-
<!-- <mgt-msal2-provider
33+
<mgt-msal2-provider
3434
client-id="2dfea037-938a-4ed8-9b35-c05708a1b241"
3535
redirect-uri="http://localhost:3000"
3636
scopes="user.read,user.read.all,mail.readBasic,people.read,people.read.all,sites.read.all,user.readbasic.all,contacts.read,presence.read,presence.read.all,tasks.readwrite,tasks.read,calendars.read,group.read.all,files.read,files.read.all,files.readwrite,files.readwrite.all"
37-
></mgt-msal2-provider> -->
37+
></mgt-msal2-provider>
3838

39-
<mgt-mock-provider></mgt-mock-provider>
39+
<!-- <mgt-mock-provider></mgt-mock-provider> -->
4040
<header>
4141
<mgt-theme-toggle></mgt-theme-toggle>
4242
</header>

packages/mgt-components/src/components/mgt-login/mgt-login.scss

+8-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
@import '../../styles/shared-styles';
1010
@import './mgt-login.theme';
1111

12-
$signed-out-bg: padding-box linear-gradient(var(--neutral-fill-rest), var(--neutral-fill-rest)), border-box var(--neutral-stroke-control-rest);
12+
$signed-out-bg: padding-box linear-gradient(var(--neutral-fill-rest), var(--neutral-fill-rest)),
13+
border-box var(--neutral-stroke-control-rest);
1314
$signed-out-background: #{var(--login-signed-out-button-background, $signed-out-bg)};
1415
$signed-out-hover-background: #{var(--login-signed-out-button-hover-background, var(--neutral-fill-stealth-hover))};
1516
$login-popup-background-color: #{var(--login-popup-background-color, var(--neutral-layer-1))};
@@ -87,15 +88,17 @@ $button-padding: var(--login-button-padding, 0);
8788
}
8889
}
8990

90-
fluent-listbox {
91-
--stroke-width: 0;
91+
.account-list {
92+
padding: calc(var(--design-unit) * 1px) 0;
93+
margin: 0;
9294
}
9395

94-
fluent-option {
96+
.account-item {
9597
height: auto;
9698
min-width: auto;
9799
margin-top: 4px;
98100
background: $login-popup-background-color;
101+
list-style-type: none;
99102

100103
&:hover {
101104
background: var(--neutral-fill-stealth-hover);
@@ -151,6 +154,5 @@ $button-padding: var(--login-button-padding, 0);
151154
}
152155
}
153156
}
154-
155157
}
156-
}
158+
}

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

+63-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { CSSResult, html, TemplateResult } from 'lit';
9-
import { property } from 'lit/decorators.js';
9+
import { property, state } from 'lit/decorators.js';
1010
import { classMap } from 'lit/directives/class-map.js';
1111
import {
1212
Providers,
@@ -186,6 +186,8 @@ export class MgtLogin extends MgtTemplatedComponent {
186186
*/
187187
private _userDetailsKey = '-userDetails';
188188

189+
@state() private _arrowKeyLocation = -1;
190+
189191
constructor() {
190192
super();
191193
this._isFlyoutOpen = false;
@@ -546,34 +548,77 @@ export class MgtLogin extends MgtTemplatedComponent {
546548

547549
if (accounts?.length > 1) {
548550
return html`
549-
<div id="accounts">
550-
<fluent-listbox class="accounts" name="Account list">
551-
${accounts.map(account => {
552-
if (account.id !== provider.getActiveAccount().id) {
551+
<div id="accounts">
552+
<ul
553+
tabindex="0"
554+
class="account-list"
555+
part="account-list"
556+
aria-label="${this.ariaLabel}"
557+
@keydown=${this.handleAccountListKeyDown}
558+
>
559+
${accounts
560+
.filter(a => a.id !== provider.getActiveAccount().id)
561+
.map(account => {
553562
const details = localStorage.getItem(account.id + this._userDetailsKey);
554563
return mgtHtml`
555-
<fluent-option class="account-option" value="${account.name}" role="option">
564+
<li
565+
tabindex="-1"
566+
part="account-item"
567+
class="account-item"
568+
@click=${() => this.setActiveAccount(account)}
569+
@keyup=${(e: KeyboardEvent) => {
570+
if (e.key === 'Enter') this.setActiveAccount(account);
571+
}}
572+
>
556573
<mgt-person
557-
@click=${() => this.setActiveAccount(account)}
558-
@keyup=${(e: KeyboardEvent) => {
559-
if (e.key === 'Enter') {
560-
this.setActiveAccount(account);
561-
}
562-
}}
563574
.personDetails=${details ? JSON.parse(details) : null}
564575
.fallbackDetails=${{ displayName: account.name, mail: account.mail }}
565576
.view=${PersonViewType.twolines}
566-
class="account"/>
567-
</fluent-option>`;
568-
}
569-
})}
570-
</fluent-listbox>
571-
</div>
577+
class="account"
578+
></mgt-person>
579+
</li>`;
580+
})}
581+
</ul>
582+
</div>
572583
`;
573584
}
574585
}
575586
}
576587

588+
private handleAccountListKeyDown = (event: KeyboardEvent) => {
589+
const list: HTMLUListElement = this.renderRoot.querySelector('ul.account-list');
590+
let item: HTMLLIElement;
591+
const listItems: HTMLCollection = list?.children;
592+
// Default all tabindex values in li nodes to -1
593+
for (const element of listItems) {
594+
const el = element as HTMLLIElement;
595+
el.setAttribute('tabindex', '-1');
596+
el.blur();
597+
}
598+
599+
const childElementCount = list.childElementCount;
600+
const keyName = event.key;
601+
if (keyName === 'ArrowDown') {
602+
this._arrowKeyLocation = (this._arrowKeyLocation + 1 + childElementCount) % childElementCount;
603+
} else if (keyName === 'ArrowUp') {
604+
this._arrowKeyLocation = (this._arrowKeyLocation - 1 + childElementCount) % childElementCount;
605+
} else if (keyName === 'Tab' || keyName === 'Escape') {
606+
this._arrowKeyLocation = -1;
607+
list.blur();
608+
if (keyName === 'Escape') {
609+
event.preventDefault();
610+
event.stopPropagation();
611+
}
612+
return;
613+
}
614+
615+
if (this._arrowKeyLocation > -1) {
616+
item = listItems[this._arrowKeyLocation] as HTMLLIElement;
617+
item.setAttribute('tabindex', '1');
618+
item.focus();
619+
}
620+
};
621+
577622
/**
578623
* Set one of the non-active accounts as the active account
579624
*

0 commit comments

Comments
 (0)