@@ -237,6 +237,18 @@ export class Alert implements ComponentInterface, OverlayInterface {
237
237
return ;
238
238
}
239
239
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
+
240
252
// The only inputs we want to navigate between using arrow keys are the radios
241
253
// ignore the keydown event if it is not on a radio button
242
254
if (
@@ -400,7 +412,19 @@ export class Alert implements ComponentInterface, OverlayInterface {
400
412
401
413
await this . delegateController . attachViewToDom ( ) ;
402
414
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
+ } ) ;
404
428
405
429
unlock ( ) ;
406
430
}
@@ -725,8 +749,8 @@ export class Alert implements ComponentInterface, OverlayInterface {
725
749
const { overlayIndex, header, subHeader, message, htmlAttributes } = this ;
726
750
const mode = getIonMode ( this ) ;
727
751
const hdrId = `alert-${ overlayIndex } -hdr` ;
728
- const subHdrId = `alert-${ overlayIndex } -sub-hdr` ;
729
752
const msgId = `alert-${ overlayIndex } -msg` ;
753
+ const subHdrId = `alert-${ overlayIndex } -sub-hdr` ;
730
754
const role = this . inputs . length > 0 || this . buttons . length > 0 ? 'alertdialog' : 'alert' ;
731
755
732
756
/**
@@ -739,12 +763,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
739
763
740
764
return (
741
765
< Host
742
- role = { role }
743
- aria-modal = "true"
744
- aria-labelledby = { ariaLabelledBy }
745
- aria-describedby = { message !== undefined ? msgId : null }
746
766
tabindex = "-1"
747
- { ...( htmlAttributes as any ) }
748
767
style = { {
749
768
zIndex : `${ 20000 + overlayIndex } ` ,
750
769
} }
@@ -761,7 +780,16 @@ export class Alert implements ComponentInterface, OverlayInterface {
761
780
762
781
< div tabindex = "0" aria-hidden = "true" > </ div >
763
782
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
+ >
765
793
< div class = "alert-head" >
766
794
{ header && (
767
795
< h2 id = { hdrId } class = "alert-title" >
0 commit comments