- π¬π§United Kingdom kalpaitch
Following on from @codebymikey's point #29 I've also identified this happens to the 'container' element too, (albeit with the caveat that the container element does not support the #description attribute):
$form['element'] = [ '#type' => 'container', '#description' => 'A description added to the container.' ];
This will result in a container wrapper being rendered with an incorrect 'aria-describedby' attribute.
Following on from @andrewmacpherson's comment #22, I agree there needs to be a more extensible way to declare a form element as a composite form element. But there are also needs to be some consideration for other render elements which get the 'aria-describedby' attribute added.
- π¨π¦Canada Liam Morland Ontario, CA π¨π¦
Liam Morland β made their first commit to this issueβs fork.
- Merge request !7117Issue #2839344: Broken aria-describedby in radios and checkboxes β (Open) created by Liam Morland
- π¨π¦Canada Liam Morland Ontario, CA π¨π¦
I have made a merge request with patch 17 rebased onto 11.x.
I agree with #25, that we should use something more extensible. However, I don't think either of the suggestions is enough information for making it work. The issue is in the
FormBuilder
class, and at that point, you don't have instances ofElementInterface
, you have a render array. So you can't do aninstanceof
test.It might be easier to add an attribute
#is_composite
to the render array?Or if I'm wrong, then I would say it's probably better to have
CompositeFormElementInterface
, because there is also aCompositeFormElementTrait
. So you could even putisComposite
in the trait, and it would be added to any contrib/custom classes using the trait as well.- πΊπΈUnited States jldust
I agree that this needs to be more extensive, I'm seeing these broken references with selection options as well.
- πΊπΈUnited States dcam
For anyone who needs a workaround, you can implement this in a custom theme or module:
/** * Implements hook_element_info_alter(). */ function my_theme_element_info_alter(array &$info) { $info['checkboxes']['#process'][] = '_my_theme_process_options_element'; $info['radios']['#process'][] = '_my_theme_process_options_element'; } /** * Processes checkboxes and radios elements. * * Checkboxes and radios have an accessibility bug where the child option * elements inherit an empty aria-describedby attribute from the parent. * Because the child elements are fully rendered before the parent, this can't * be handled in preprocess functions. * * @param array $element * An options form element. * * @return array * The processed options form element. * * @see https://www.drupal.org/project/drupal/issues/2839344 */ function _my_theme_process_options_element(array $element) { foreach ($element as $key => $value) { if (substr((string) $key, 0, 1) == '#') { continue; } if (!isset($value['#description']) && isset($value['#attributes']['aria-describedby'])) { unset($value['#attributes']['aria-describedby']); $element[$key] = $value; } } return $element; }
The same thing can be accomplished by adding a process function to individual checkbox and radio buttons. I tested it. Doing that means you don't need to loop through all the keys in the parent element to find its children. But my preference was to target the checkboxes and radios since they're the ones that have the problem.
- πΊπΈUnited States dcam
I disagree with the approach in MR 7117 and from reading through comments it was contentious to begin with.
I spent the last couple of evenings studying the checkboxes and radios form elements, trying to figure out what parts of the system were setting wrappers and IDs and descriptions. I wanted to make absolutely certain that I'd found the source of these attributes so that it could be solved there.
It's the Checkboxes and Radios form element classes that do it. They both copy the parent element's attributes to the children, including the
aria-describedby
. This choice is made unilaterally by those classes. The rest of the form system, e.g. FormBuilder, is just doing what it's supposed to do. Also, the element classes are also managing the child descriptions or rather the lack of them. So if the element classes are setting the attributes, then they should be in charge of unsetting any irrelevant attributes. I opened MR 12287 with this strategy in mind. If this idea is accepted, then MR 7117 should be closed.I can sympathize with any desire to not duplicate code, but I will note that there is already a lot of duplicated code between the two elements. I probably wouldn't bother. If someone wants that to happen, then I assert that we should put off eliminating duplication for a follow-up.