Problem/Motivation
Required fields in Form API have both the required="required"
attribute as well as the aria-required="true"
attribute.
- This is flagged in Siteimprove as a WCAG Level A warning, with the following generic text:
A WAI-ARIA attribute that has the exact same features as the HTML element it has been applied to has been used. The WAI-ARIA attribute is redundant since is doesn't provide the user with any additional information.
For landmarks it has previously been a recommendation to use HTML5 and WAI-ARIA landmark roles together (e.g. WAI-ARIA role="navigation" on HTML5 'nav' elements) to maximize support, but with the widespread adoption of HTML5 this is no longer needed.
Where to find it in WCAG 2:
4 Robust > 4.1 Compatible > A > 4.1.2 Name, Role, Value > Warning > Redundant WAI-ARIA attribute - According to On HTML belts and ARIA braces (The Default Implicit ARIA semantics they didn’t want you to know about) by Steve Faulkner — one of the editors of the ARIA spec — adding the 'aria-required' in addition to the native HTML 'required' attribute is a, quote, “waste of time” since it is already set by the browser, as can be seen in https://stevefaulkner.github.io/html-mapping-tests .
Steps to reproduce
Inspect a node edit screen and look at any required field, such as node title.
Proposed resolution
Siteimprove suggests the following fix:
The WAI-ARIA attribute can be removed without any impact for end users. The result will be cleaner, easier to maintain code.
The suggested changes would affect Drupal Core in these places:
setAttributes
method of core/lib/Drupal/Core/Render/Element/RenderElement.php:// This function is invoked from form element theme functions, but the // rendered form element may not necessarily have been processed by // \Drupal::formBuilder()->doBuildForm(). if (!empty($element['#required'])) { $element['#attributes']['class'][] = 'required'; $element['#attributes']['required'] = 'required'; $element['#attributes']['aria-required'] = 'true'; #<-- HERE }
$document.on('state:required'
of core/misc/states.es6.js.if (e.value) { const label = `label${e.target.id ? `[for=${e.target.id}]` : ''}`; const $label = $(e.target) .attr({ required: 'required', 'aria-required': 'true' }) /*<-- HERE */ .closest('.js-form-item, .js-form-wrapper') .find(label); // Avoids duplicate required markers on initialization. if (!$label.hasClass('js-form-required').length) { $label.addClass('js-form-required form-required'); } } else { $(e.target) .removeAttr('required aria-required') /*<-- HERE */ .closest('.js-form-item, .js-form-wrapper') .find('label.js-form-required') .removeClass('js-form-required form-required'); }
The addition of aria-required
in addition to the required attribute was done over 10 years ago in #1174938: Natively support the HTML5 required and aria-required FAPI properties.
Remaining tasks
- Validate that this is an actual bug or a red herring from Siteimprove.
- If bug, write a patch with tests.
- If red herring, write to Siteimprove to fix their tests.