Question

Given a checkbox field with two options:

  • "Closed" (selected by default)
  • "Open"

I'd like to expand or collapse the <details> container of a different field (in our specific case an Address field). In HTML terms, this means adding the open HTML5 attribute to the <details> tag and adding aria-expanded=true to the <summary> tag when the "Open" radio button value is clicked, and ensure it is removed when that radio option is not selected (which means by default at page load time as well).

I've found a few older semi-related issues and the documentation page for Drupal 8's drupal_process_states, but it's looking like this isn't possible with the Form #states API in Drupal 8. The docs do not include "open" in the list of valid states that may be applied to an element.

The valid states are:

  • enabled
  • disabled
  • required
  • optional
  • visible
  • invisible
  • checked
  • unchecked
  • expanded
  • collapsed

One would think that maybe the expanded and collapsed options could work, however this does not seem to be the case with my sample code below:

function mymodule_form_node_<type>_form_alter(&$form, FormStateInterface $form_state) {
  $form['field_address']['#states'] = [
    // Expand address field container when the Trigger field is 'Open'.
    'expanded' => [
      ':input[name="field_trigger"]' => [
        'value' => 'open'
      ],
    ],
  ];
}

Replacing 'expanded' state with 'open' in the above does not work, nor does the inverse logic using 'collapsed' state work:

function mymodule_form_node_<type>_form_alter(&$form, FormStateInterface $form_state) {
  $form['field_address']['#states'] = [
    // Collapse address field container when the Trigger field is 'Closed'.
    'collapsed' => [
      ':input[name="field_trigger"]' => [
        'value' => 'closed'
      ],
    ],
  ];
}

No correct solution

OTHER TIPS

Rather than using expanded/collapsed use open/close like below:

function mymodule_form_node_<type>_form_alter(&$form, FormStateInterface $form_state) {
  $form['field_address']['#states'] = [
    // Expand address field container when the Trigger field is 'Open'.
    'open' => [
      ':input[name="field_trigger"]' => [
        'value' => 'open'
      ],
    ],
    'close' => [
      ':input[name="field_trigger"]' => [
        'value' => 'closed'
      ],
    ],
  ];
}

Unfortunately, I'm going to answer my own question: expanded and collapsed states do work for the <details> type.

My problem was operator error. I was adding the #states array at the level of the '#type' => 'container' but the container has a widget inside of it that holds the '#type' => 'details'. Fun times with Form API!

The working code is this:

<?php
// In mymodule.module
use \Drupal\Core\Form\FormStateInterface;

function mymodule_form_node_<type>_form_alter(&$form, FormStateInterface $form_state) {
  $form['field_address']['widget'][0]['#states'] = [
    // Expand location field when the Type is 'On-site'.
    'expanded' => [
      ':input[name="field_trigger"]' => [
        'value' => 'open'
      ],
    ],
    // Collapse location field when the Type is 'Online'.
    'collapsed' => [
      ':input[name="field_trigger"]' => [
        'value' => 'closed'
      ],
    ],
  ];

  // Load edit form with Location field either open or closed, based
  // on the value of the Trigger field.
  $form['field_address']['widget'][0]['#open'] = ($form['field_trigger']['widget']['#default_value'] == 'open') ? 1 : 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with drupal.stackexchange
scroll top