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.

| Comment | File | Size | Author |
|---|
Issue fork drupal-3267246
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
Comment #2
quietone commentedIs this a duplicate of #2731991: Setting required on radios marks all options required ?
Comment #3
bklineDon't think so. That issue appears to be reporting the opposite of what I'm seeing.
Comment #5
gaurav_manerkar commentedHi,
I am facing same issue.
Comment #6
bklineComment #7
bhanu951 commentedComment #8
quietone commentedThere are more issues about checkbox, there is this one about required, #3267246: ['#states']['required'] broken for radios. Maybe a duplicate?
Comment #9
spokjeErm...that's a link to this issue, maybe a c/p error and you did find a potential duplicate?
Comment #10
darrenwh commentedI've found if you wrap a radio field in a fieldset and disable the fieldset this works.
Comment #11
nevergoneContrib blocker, see: #3333665: [3.x] Settings form refactoring
Comment #12
dwwHere's a much simpler failing test than what's described in the summary. 😅
It's basically just this:
Comment #13
quietone commented@Spokje, yes, that is wrong. #2951317: Radios element missing "required" attribute.
This also needs a better title, one that explains what is being fixed.
Comment #14
dwwHrm, 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.
Comment #15
larowlanWhat 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.
Comment #16
gappleThis may be because of #2945727: Form radios/checkboxes elements should have js-form-wrapper class?
Comment #18
nevergoneHow can the resolution of this proceed?
Comment #19
nevergoneHow could this be fixed?
Comment #20
bkline@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).
Comment #21
mortona2k commentedI 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.
Comment #23
jcandan commentedRE: #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
_nonevalue 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.
Comment #24
jcandan commentedComment #25
jcandan commentedScratch #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.
Comment #26
jcandan commentedClosing as outdated, since this state change is best captured in #2951317: Radios element missing "required" attribute.