diff --git a/classes/models/FrmFieldFormHtml.php b/classes/models/FrmFieldFormHtml.php index 98634b3431..e9dc690408 100644 --- a/classes/models/FrmFieldFormHtml.php +++ b/classes/models/FrmFieldFormHtml.php @@ -526,6 +526,11 @@ private function add_multiple_input_attributes() { $attributes['aria-required'] = 'true'; } + // Add 'aria-invalid' attribute to the group if there are errors. + if ( isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ) { + $attributes['aria-invalid'] = 'true'; + } + // Concatenate attributes into a string, and replace the role="group" in the HTML with the attributes string. $html_attributes = FrmAppHelper::array_to_html_params( $attributes ); $this->html = str_replace( ' role="group"', $html_attributes, $this->html ); diff --git a/classes/models/fields/FrmFieldCheckbox.php b/classes/models/fields/FrmFieldCheckbox.php index 41bc9dc51f..7b1f2819ec 100644 --- a/classes/models/fields/FrmFieldCheckbox.php +++ b/classes/models/fields/FrmFieldCheckbox.php @@ -108,4 +108,17 @@ protected function show_readonly_hidden() { protected function prepare_import_value( $value, $atts ) { return $this->get_multi_opts_for_import( $value ); } + + /** + * Unset aria-invalid for checkboxes because it's not valid for checkboxes. + * Instead aria-invalid is added to the checkbox group parent element. + * + * @since x.x + * + * @param array $shortcode_atts + * @param array $args + */ + public function set_aria_invalid_error( &$shortcode_atts, $args ) { + unset( $shortcode_atts['aria-invalid'] ); + } } diff --git a/classes/models/fields/FrmFieldRadio.php b/classes/models/fields/FrmFieldRadio.php index b21d30f5d9..d8d62e57f6 100644 --- a/classes/models/fields/FrmFieldRadio.php +++ b/classes/models/fields/FrmFieldRadio.php @@ -109,4 +109,17 @@ protected function include_front_form_file() { protected function show_readonly_hidden() { return true; } + + /** + * Unset aria-invalid for radio buttons because it's not valid for radio buttons. + * Instead aria-invalid is added to the radiogroup parent element. + * + * @since x.x + * + * @param array $shortcode_atts + * @param array $args + */ + public function set_aria_invalid_error( &$shortcode_atts, $args ) { + unset( $shortcode_atts['aria-invalid'] ); + } } diff --git a/js/formidable.js b/js/formidable.js index 451232fdf9..df085fc7eb 100644 --- a/js/formidable.js +++ b/js/formidable.js @@ -1147,7 +1147,12 @@ function frmFrontFormJS() { input.attr( 'aria-describedby', describedBy ); } - input.attr( 'aria-invalid', true ); + + if ( [ 'radio', 'checkbox' ].includes( input.attr( 'type' ) ) ) { + input.closest( '[role="radiogroup"], [role="group"]' ).attr( 'aria-invalid', true ); + } else { + input.attr( 'aria-invalid', true ); + } jQuery( document ).trigger( 'frmAddFieldError', [ $fieldCont, key, jsErrors ] ); } @@ -1186,8 +1191,13 @@ function frmFrontFormJS() { fieldContainer.classList.remove( 'frm_blank_field', 'has-error' ); } + if ( 'true' === input.attr( 'aria-invalid' ) ) { + input.attr( 'aria-invalid', false ); + } else if ( [ 'radio', 'checkbox' ].includes( input.attr( 'type' ) ) ) { + input.closest( '[role="radiogroup"], [role="group"]' ).attr( 'aria-invalid', false ); + } + errorMessage.remove(); - input.attr( 'aria-invalid', false ); input.removeAttr( 'aria-describedby' ); if ( typeof describedBy !== 'undefined' ) {