diff --git a/classes/helpers/FrmFormsHelper.php b/classes/helpers/FrmFormsHelper.php index b9da117e58..d858d58bc1 100644 --- a/classes/helpers/FrmFormsHelper.php +++ b/classes/helpers/FrmFormsHelper.php @@ -532,7 +532,10 @@ public static function get_success_message( $atts ) { $message = do_shortcode( $message ); $role = $atts['role'] ?? 'status'; - return '
' . $message . '
'; + // tabindex="-1" makes the success message programmatically focusable without adding it + // to the tab order, so js/formidable.js can focus it after an AJAX submit without a + // screen reader user having to tab to it. + return '
' . $message . '
'; } /** diff --git a/js/formidable.js b/js/formidable.js index 41c018a4bd..4b57e6a1b4 100644 --- a/js/formidable.js +++ b/js/formidable.js @@ -944,7 +944,9 @@ function frmFrontFormJS() { function() { afterFormSubmittedBeforeReplace( object, response ); - replaceContent.replaceWith( response.content ); + const insertedContent = jQuery( response.content ); + replaceContent.replaceWith( insertedContent ); + focusFormMessage( insertedContent ); addUrlParam( response ); @@ -1070,6 +1072,24 @@ function frmFrontFormJS() { jQuery.ajax( ajaxParams ); // eslint-disable-line no-jquery/no-ajax } + /** + * Move focus to the top-level success message after an AJAX submit, so screen reader + * users are notified it appeared. Scoped to `insertedContent` (the markup that just + * replaced the form) rather than a wider ancestor, so an unrelated `.frm_message`-classed + * element elsewhere on the page can never be focused instead. + * + * @since x.x + * + * @param {jQuery} insertedContent The markup that just replaced the form. + * @return {void} + */ + function focusFormMessage( insertedContent ) { + const message = insertedContent.filter( '.frm_message' ).add( insertedContent.find( '.frm_message' ) ).get( 0 ); + if ( message ) { + focusInput( message ); + } + } + function afterFormSubmitted( object, response ) { const tempDiv = document.createElement( 'div' ); tempDiv.innerHTML = response.content; diff --git a/tests/cypress/e2e/admin.cy.js b/tests/cypress/e2e/admin.cy.js index 80941a8a93..f5557f80fa 100644 --- a/tests/cypress/e2e/admin.cy.js +++ b/tests/cypress/e2e/admin.cy.js @@ -37,7 +37,11 @@ describe( 'Run some basic Formidale tests', function() { cy.get( '#frm_form_key' ).invoke( 'val' ).then( formKey => { cy.visit( `/wp-admin/admin-ajax.php?action=frm_forms_preview&form=${ formKey }` ); cy.get( '.frm_button_submit' ).should( 'contain.text', 'Submit' ).click(); - cy.get( '.frm_message' ).should( 'contain.text', 'Your responses were successfully submitted. Thank you!' ); + + // Focus should move to the success message so screen reader users are notified it appeared. + cy.get( '.frm_message' ) + .should( 'contain.text', 'Your responses were successfully submitted. Thank you!' ) + .and( 'be.focused' ); } ); } ); } );