@@ -320,6 +320,7 @@ export class MgtLogin extends MgtTemplatedComponent {
320320 const expandedState : boolean | undefined = showSignedInState ? this . _isFlyoutOpen : undefined ;
321321 return html `
322322 < fluent-button
323+ id ="login-button "
323324 aria-expanded ="${ ifDefined ( expandedState ) } "
324325 appearance =${ appearance }
325326 aria-label ="${ ifDefined ( isSignedIn ? undefined : this . strings . signInLinkSubtitle ) } "
@@ -351,14 +352,49 @@ export class MgtLogin extends MgtTemplatedComponent {
351352 light-dismiss
352353 @opened =${ this . flyoutOpened }
353354 @closed =${ this . flyoutClosed } >
354- < div slot ="flyout ">
355- < fluent-card class ="flyout-card ">
356- ${ this . renderFlyoutContent ( ) }
357- </ fluent-card >
358- </ div >
355+ < fluent-card
356+ slot ="flyout "
357+ tabindex ="0 "
358+ class ="flyout-card "
359+ @keydown =${ this . onUserKeyDown }
360+ >
361+ ${ this . renderFlyoutContent ( ) }
362+ </ fluent-card >
359363 </ mgt-flyout > ` ;
360364 }
361365
366+ /**
367+ * Tracks tabbing through the flyout (keydown)
368+ */
369+ private readonly onUserKeyDown = ( e : KeyboardEvent ) : void => {
370+ if ( ! this . flyout . isOpen ) {
371+ return ;
372+ }
373+
374+ const el = this . renderRoot . querySelector ( '.popup-content' ) ;
375+ const focusableEls = el . querySelectorAll ( 'ul, fluent-button' ) ;
376+ const firstFocusableEl = el . querySelector ( '#signout-button' ) || focusableEls [ 0 ] ;
377+ const lastFocusableEl =
378+ el . querySelector ( '#signin-different-account-button' ) || focusableEls [ focusableEls . length - 1 ] ;
379+
380+ if ( e . key === 'Tab' && e . shiftKey && firstFocusableEl === e . target ) {
381+ e . preventDefault ( ) ;
382+ ( lastFocusableEl as HTMLElement ) ?. focus ( ) ;
383+ }
384+ if ( e . key === 'Tab' && ! e . shiftKey && lastFocusableEl === e . target ) {
385+ e . preventDefault ( ) ;
386+ ( firstFocusableEl as HTMLElement ) ?. focus ( ) ;
387+ }
388+ if ( e . key === 'Escape' ) {
389+ const loginButton = this . renderRoot . querySelector ( '#login-button' ) ;
390+ ( loginButton as HTMLElement ) ?. focus ( ) ;
391+ }
392+ const fluentCardEl = this . renderRoot . querySelector ( 'fluent-card' ) ;
393+ if ( e . shiftKey && e . key === 'Tab' && e . target === fluentCardEl ) {
394+ this . hideFlyout ( ) ;
395+ }
396+ } ;
397+
362398 /**
363399 * Render the flyout menu content.
364400 *
@@ -435,6 +471,7 @@ export class MgtLogin extends MgtTemplatedComponent {
435471 template ||
436472 html `
437473 < fluent-button
474+ id ="signout-button "
438475 appearance ="stealth "
439476 size ="medium "
440477 class ="flyout-command "
@@ -472,6 +509,7 @@ export class MgtLogin extends MgtTemplatedComponent {
472509 return html `
473510 < div class ="add-account ">
474511 < fluent-button
512+ id ="signin-different-account-button "
475513 appearance ="stealth "
476514 aria-label ="${ this . strings . signInWithADifferentAccount } "
477515 @click =${ ( ) => void this . login ( ) } >
0 commit comments