['#states']['required'] broken for radios

Created on 1 March 2022, about 3 years ago
Updated 29 March 2024, 11 months ago

Problem/Motivation

According to the FormHelper documentation, required is one of the states which may be applied dynamically to a form element. This works for some Drupal form elements, but not for an element whose type is 'radios'.

Steps to reproduce

Install the following code for a form class.


namespace Drupal\test\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class Repro extends FormBase {
  public function getFormId(): string { return 'test_repro_form'; }
  public function buildForm($form, FormStateInterface $form_state) {
    return [
      'f0' => [
        '#type' => 'radios',
        '#title' => 'F0',
        '#options' => [1 => 'Un', 2 => 'Deux', 3 => 'Trois'],
      ],
      'f1' => [
        '#type' => 'radios',
        '#title' => 'F1',
        '#options' => [1 => 'Uno', 2 => 'Dos', 3 => 'Tres'],
        '#required' => TRUE,
        '#states' => [
          'visible' => [':input[name="f0"]' => ['value' => 1]],
        ],
      ],
      'f2' => [
        '#type' => 'radios',
        '#title' => 'F2',
        '#options' => [1 => 'Eins', 2 => 'Zwo', 3 => 'Drei'],
        '#states' => [
          'visible' => [':input[name="f0"]' => ['value' => 2]],
          'required' => [':input[name="f0"]' => ['value' => 2]],
        ],
      ],
      'f3' => [
        '#type' => 'textfield',
        '#title' => 'F3',
        '#states' => [
          'visible' => [':input[name="f0"]' => ['value' => 3]],
          'required' => [':input[name="f0"]' => ['value' => 3]],
        ],
      ],
      'submit' => [
        '#type' => 'submit',
        '#value' => 'Submit',
      ],
    ];
  }
  public function submitForm(array &$form, FormStateInterface $form_state) {
    dpm($form_state->getValues());
  }
}

Add the routing:

test.repro:
  path: '/test/repro'
  defaults:
    _title: 'Test Repro Form'
    _form: Drupal\test\Form\Repro
  requirements:
    _access: 'TRUE'

Bring up the form in a browser, and confirm the following:

  • The "visible" state is applied correctly for all three of the fields for which #state is present, confirming that #state is at the correct level in the hierarchy.
  • The radios for field F1 are visually identified as required, and form submission is blocked if one of its radio buttons is not selected, so unconditional requirement of a "radios" element works correctly.
  • If you make the F1 field visible (by clicking the first radio button of the F0 field) and select one of its radio buttons (to bypass the unconditional "required" check for that field) and then make the F3 field visible (by clicking the last radio button of the F0 field), you will see that the text field F3 is visually identified as required, and form submission is blocked if the field is left empty, confirming that the "required" state works correctly for text fields.
  • If a radio button is selected for the F1 field as described above, and then the middle radio button of the F0 field is clicked, making the F2 field visible, you will see that there is no visible indication that this field is required (in contrast to fields F1 and F3), and no check is performed to ensure that a value is selected for the field at form submission.

Proposed resolution

Make the "required" state behave correctly for "radios" elements.

Remaining tasks

Improve title
review
Add before and after screenshots to the User interface changes

User interface changes

TBA

Versions

  • Drupal 9.3.6
  • Web server: Apache/2.4.41
  • PHP 7.4.3
  • OS Linux 5.4.0 (Ubuntu 20.4)

Screenshots

This is the initial form. As expected none of the fields with dynamic visibility are rendered.

The unconditionally required radios element behaves correctly.

The conditionally required text field also behaves as expected.

The dynamic "required" state for radios, by contrast, is broken. There is no visible indication that one of the F2 radio buttons must be selected, and submitting the form in the absence of such a selection does not trigger a validation error.

πŸ› Bug report
Status

Needs work

Version

11.0 πŸ”₯

Component
FormΒ  β†’

Last updated 3 days ago

Created by

πŸ‡ΊπŸ‡ΈUnited States bkline Virginia

Live updates comments and jobs are added and updated live.
  • Contributed project blocker

    It denotes an issue that prevents porting of a contributed project to the stable version of Drupal due to missing APIs, regressions, and so on.

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.

  • πŸ‡­πŸ‡ΊHungary nevergone NyΓ­regyhΓ‘za, Hungary, Europe

    Contrib blocker, see: πŸ› Settings form refactoring Active

  • Status changed to Needs work almost 2 years ago
  • πŸ‡ΊπŸ‡ΈUnited States dww

    Here's a much simpler failing test than what's described in the summary. πŸ˜…

    It's basically just this:

        $form['checkbox_trigger'] = [
          '#type' => 'checkbox',
          '#title' => 'Checkbox trigger',
        ];
        $form['radios_required_when_checkbox_trigger_checked'] = [
          '#type' => 'radios',
          '#title' => 'Radios required when checkbox trigger checked',
          '#options' => [
            'value1' => 'Value 1',
            'value2' => 'Value 2',
          ],
          '#states' => [
            'required' => [
              ':input[name="checkbox_trigger"]' => ['checked' => TRUE],
            ],
          ],
        ];
    
  • πŸ‡³πŸ‡ΏNew Zealand quietone

    @Spokje, yes, that is wrong. πŸ› Radios element missing "required" attribute Needs work .

    This also needs a better title, one that explains what is being fixed.

  • πŸ‡ΊπŸ‡ΈUnited States dww

    Hrm, looking more closely, that test isn't exactly right, either. There's weirdness with what element we're selecting when it comes to 'radios'. Are we targetting the fieldset, or the input, or...? But, it's a start. πŸ˜… The form changes are fine. We probably just need to be more specific with how we select which elements we're manipulating in the test itself.

    And yeah, in light of πŸ› Radios element missing "required" attribute Needs work , we may want/need to change which elements are getting the required attribute, anyway.

  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    What happens in this scenario:

    * user checks box to make radio required
    * user selects a radio
    * user unselects checkbox to make radio visible

    In that scenario the radio option selected in step 2 would still be sent, there's no way to unset a radio in a set of radios once set.

  • πŸ‡¨πŸ‡¦Canada gapple

    This may be because of πŸ› Form radios/checkboxes elements should have js-form-wrapper class Postponed: needs info ?

  • πŸ‡­πŸ‡ΊHungary nevergone NyΓ­regyhΓ‘za, Hungary, Europe

    How can the resolution of this proceed?

  • πŸ‡­πŸ‡ΊHungary nevergone NyΓ­regyhΓ‘za, Hungary, Europe

    How could this be fixed?

  • πŸ‡ΊπŸ‡ΈUnited States bkline Virginia

    @larowlan (#15) Sorry for the delayed response. Yes, I believe it's true that Drupal provides no way to prevent the return of values entered/selected on one path when the user changes his/her mind and selects another path (a mythical #forbidden mirror image of #required), and it's also true that (short of reloading the form and starting over) the user can't back out of having a selection for a set of radio buttons once a selection has been made. But that just means that the submit handler just has to be intelligent about what it needs, based on the state of the field which determines which path was taken by the user when the form was submitted. In other words, it's not a big deal that the handler might get more than it needs, but it is a problem that it might get fewer values than are needed (and that the rendering of the form fails to convey the fact that the field is required).

Production build 0.71.5 2024