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.
Initial form
The unconditionally required radios element behaves correctly.
Unconditionally controlled field
The conditionally required text field also behaves as expected.
Dynamically required text field
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.
Dynamically required radios

Issue fork drupal-3267246

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

bkline created an issue. See original summary.

quietone’s picture

bkline’s picture

Don't think so. That issue appears to be reporting the opposite of what I'm seeing.

  1. It's describing situations in which Drupal is marking all of the options, not just the field, whereas I'm describing behavior which fails to apply any visible indications of a required state.
  2. That issue is about the visible appearance of the form, but this one is reporting the failure to prevent the form from being submitted with a required value missing.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

gaurav_manerkar’s picture

Hi,

I am facing same issue.

bkline’s picture

Issue summary: View changes
bhanu951’s picture

Version: 9.4.x-dev » 10.1.x-dev
quietone’s picture

There are more issues about checkbox, there is this one about required, #3267246: ['#states']['required'] broken for radios. Maybe a duplicate?

spokje’s picture

Erm...that's a link to this issue, maybe a c/p error and you did find a potential duplicate?

darrenwh’s picture

I've found if you wrap a radio field in a fieldset and disable the fieldset this works.

nevergone’s picture

dww’s picture

Status: Active » Needs work
StatusFileSize
new3.82 KB

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],
        ],
      ],
    ];
quietone’s picture

Issue summary: View changes

@Spokje, yes, that is wrong. #2951317: Radios element missing "required" attribute.

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

dww’s picture

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 #2951317: Radios element missing "required" attribute, we may want/need to change which elements are getting the required attribute, anyway.

larowlan’s picture

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.

gapple’s picture

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nevergone’s picture

How can the resolution of this proceed?

nevergone’s picture

How could this be fixed?

bkline’s picture

@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).

mortona2k’s picture

I am also encountering this issue with checkboxes.

The field with checkboxes should be visible and required when a select list has a certain value. Hiding it is working, but making it required is not. Setting the field to required, and using states to make it optional is also not working.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

jcandan’s picture

RE: #20

But, for other form field types, state handling is just a front-end change, and conditionally-required validation passes simply as a matter of removing that field's empty value from the form POST, right?

So, as a matter of state handling, shouldn't we just ensure the _none value is passed if a radio is conditionally required but unselected, and wiped of that value when it is conditionally, subsequently un-required.

It seems the N/A option being marked-selected and hidden is the movement to be made.

jcandan’s picture

Assigned: Unassigned » jcandan
jcandan’s picture

Assigned: jcandan » Unassigned

Scratch #23, I was describing how Conditional Fields module handles validation.

States is front-end only. That said, I agree with #2951317: Radios element missing "required" attribute that the required attribute and class handling should follow WCAG (see here, here).

Since that ticket manipulates initial placement, it should also handle state changes. I suggest we capture this fix there.

jcandan’s picture

Status: Needs work » Closed (outdated)

Closing as outdated, since this state change is best captured in #2951317: Radios element missing "required" attribute.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.