@@ -237,6 +237,18 @@ export class Alert implements ComponentInterface, OverlayInterface {
237237 return ;
238238 }
239239
240+ /**
241+ * Ensure when alert container is being focused, and the user presses the tab + shift keys, the focus will be set to the last alert button.
242+ */
243+ if ( ev . target . classList . contains ( 'alert-wrapper' ) ) {
244+ if ( ev . key === 'Tab' && ev . shiftKey ) {
245+ ev . preventDefault ( ) ;
246+ const lastChildBtn = this . wrapperEl ?. querySelector ( '.alert-button:last-child' ) as HTMLButtonElement ;
247+ lastChildBtn . focus ( ) ;
248+ return ;
249+ }
250+ }
251+
240252 // The only inputs we want to navigate between using arrow keys are the radios
241253 // ignore the keydown event if it is not on a radio button
242254 if (
@@ -400,7 +412,19 @@ export class Alert implements ComponentInterface, OverlayInterface {
400412
401413 await this . delegateController . attachViewToDom ( ) ;
402414
403- await present ( this , 'alertEnter' , iosEnterAnimation , mdEnterAnimation ) ;
415+ await present ( this , 'alertEnter' , iosEnterAnimation , mdEnterAnimation ) . then ( ( ) => {
416+ /**
417+ * Check if alert has only one button and no inputs.
418+ * If so, then focus on the button. Otherwise, focus the alert wrapper.
419+ * This will map to the default native alert behavior.
420+ */
421+ if ( this . buttons . length === 1 && this . inputs . length === 0 ) {
422+ const queryBtn = this . wrapperEl ?. querySelector ( '.alert-button' ) as HTMLButtonElement ;
423+ queryBtn . focus ( ) ;
424+ } else {
425+ this . wrapperEl ?. focus ( ) ;
426+ }
427+ } ) ;
404428
405429 unlock ( ) ;
406430 }
@@ -725,8 +749,8 @@ export class Alert implements ComponentInterface, OverlayInterface {
725749 const { overlayIndex, header, subHeader, message, htmlAttributes } = this ;
726750 const mode = getIonMode ( this ) ;
727751 const hdrId = `alert-${ overlayIndex } -hdr` ;
728- const subHdrId = `alert-${ overlayIndex } -sub-hdr` ;
729752 const msgId = `alert-${ overlayIndex } -msg` ;
753+ const subHdrId = `alert-${ overlayIndex } -sub-hdr` ;
730754 const role = this . inputs . length > 0 || this . buttons . length > 0 ? 'alertdialog' : 'alert' ;
731755
732756 /**
@@ -739,12 +763,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
739763
740764 return (
741765 < Host
742- role = { role }
743- aria-modal = "true"
744- aria-labelledby = { ariaLabelledBy }
745- aria-describedby = { message !== undefined ? msgId : null }
746766 tabindex = "-1"
747- { ...( htmlAttributes as any ) }
748767 style = { {
749768 zIndex : `${ 20000 + overlayIndex } ` ,
750769 } }
@@ -761,7 +780,16 @@ export class Alert implements ComponentInterface, OverlayInterface {
761780
762781 < div tabindex = "0" aria-hidden = "true" > </ div >
763782
764- < div class = "alert-wrapper ion-overlay-wrapper" ref = { ( el ) => ( this . wrapperEl = el ) } >
783+ < div
784+ class = "alert-wrapper ion-overlay-wrapper"
785+ role = { role }
786+ aria-modal = "true"
787+ aria-labelledby = { ariaLabelledBy }
788+ aria-describedby = { message !== undefined ? msgId : null }
789+ tabindex = "0"
790+ ref = { ( el ) => ( this . wrapperEl = el ) }
791+ { ...( htmlAttributes as any ) }
792+ >
765793 < div class = "alert-head" >
766794 { header && (
767795 < h2 id = { hdrId } class = "alert-title" >
0 commit comments