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.