Improve #radios required validation and error placement.

Created on 21 August 2020, almost 4 years ago
Updated 10 December 2023, 7 months ago

Problem/Motivation

Current Behavior:
When building custom form with #radios only #attributes are passed to the individual #radio elements. We can still access the CvValidator 'required' by setting #attributes => ['required' => ''] however the error message will still appear next to the first radio in the set and display a misleading message like '{Option Label} is required'.

Expected Behavior:
When building custom form with #radios I can use #required and #required_error and the radio children will inherit the validator criteria. When submitting a form with a type #radios without selecting a radio, I expect the configured #required_error to appear beneath the of the wrapping fieldset like IFE.

Proposed resolution

Optional:
Leverage patch on https://www.drupal.org/project/drupal/issues/2951317 🐛 Radios element missing "required" attribute Needs work to allow #required to be passed to radio elements.
If you don't use the above patch, the CvValidator required plugin can still be triggered on radio via "#attributes => ['required' => ' ']"

For passing #required_error to radio elements:
Add conditional to Required.php that checks for #type => radio. If radio is not required and has parent #radios, run getRules on the parent, so we can access the #required_error.

To alter position of radios error message:
Add errorPlacement callback to cv.jquery.ife.js and insert beneath of the closest fieldset with data-drupal-selector that matches the errored radios data-drupal-selector without its radio index.

Remaining tasks

Add the patch.

API changes

// With a patch from https://www.drupal.org/project/drupal/issues/2951317 🐛 Radios element missing "required" attribute Needs work
$form['radios'] = [
'#type' => 'radios',
'#title' => $this->t('How many Drupal sites have you built?'),
'#options' => $options_array,
'#required' => TRUE,
'#required_error' => 'Custom message',
];

// Without patch from https://www.drupal.org/project/drupal/issues/2951317 🐛 Radios element missing "required" attribute Needs work .
$form['radios'] = [
'#type' => 'radios',
'#title' => $this->t('How many Drupal sites have you built?'),
'#options' => $options_array,
'#required' => TRUE, // continue to include so fieldset is rendered as required.
'#attributes' => [
'required' => ' ', // passed to #radio elements and caught by Required validator plugin.
],
'#required_error' => 'Custom message',
];

Feature request
Status

Needs work

Version

4.0

Component

Code

Created by

Live updates comments and jobs are added and updated live.
  • Accessibility

    It affects the ability of people with disabilities or special needs (such as blindness or color-blindness) to use Drupal.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇺🇸United States dystopianblue

    Confirmed, #8 works. Make sure to enable `inline_form_errors` which I had forgot to do, causing it not to work initially.

  • 🇪🇸Spain pakmanlh Barcelona

    I can confirm #8 works but sometimes the assumption of $complete_form['#type'] always existing can generate warning messages, for instance when you access `/admin/config/regional/language`when you have language module active.
    I just added a check to mitigate this situation. Thanks!

  • 🇧🇷Brazil andre.bonon

    Hi, thanks everyone for your contribution to this issue.
    I tried to fix the issue using your approach for webforms (clientside_validation + webform_clientside_validation + inline_form_errors), but the issue was still happening.
    In my case, my theme extends from stable9 that doesn't add classes like "form-checkboxes", "form-radios", or "form-type-[type]" to the form elements, which are used in the webform_clientside_validation js selectors.
    Stable9 adds "js-form-type-[type]" and forgets about the "form-type-[type]" as in the snippet below:

    {%
      set classes = [
        'js-form-item',
        'form-item',
    +        'form-type-' ~ type|clean_class, (THIS IS MISSING)
        'js-form-type-' ~ type|clean_class,
        'form-item-' ~ name|clean_class,
        'js-form-item-' ~ name|clean_class,
        title_display not in ['after', 'before'] ? 'form-no-label',
        disabled == 'disabled' ? 'form-disabled',
        errors ? 'form-item--error',
      ]
    %}

    I fixed the placement issue by overriding the form-element.html.twig and adding the code above. For the fieldset.html.twig, I added the following:

    {%
      set classes = [
      'js-form-item',
      'form-item',
      'js-form-wrapper',
      'form-wrapper',
    +  'form-' ~ element['#type'] (THIS IS MISSING)
    ]
    
  • 🇧🇷Brazil andre.bonon

    I reported this core bug https://www.drupal.org/project/drupal/issues/3380021 🐛 Stable9 form-element template misses form-type-* class Fixed , so it might avoid issues with themes based on stable9.

  • 🇨🇦Canada igorbiki

    Solution/patch #12 works for me. Both radios and checkboxes (as webforms elements) display error messages beneath all options.

  • 🇮🇳India nikunjkotecha India, Gujarat, Rajkot

    Thanks everyone, I would really appreciate if we can have some tests added to the patch.

    I am trying to reproduce and confirm the fix and improve the solution (make it generic and work even without inline_form_errors module), I have got radios working but not able to make normal required validation work for checkboxes.

Production build 0.69.0 2024