4

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'
      ],
    ],
  ];
}
1

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'
      ],
    ],
  ];
}
  • I mentioned in passing on OP that I tried this and it didn't work. I've tried again to be sure, and I can't make it work. Are you sure there is code in Drupal 8 that works with open/close states? – JamesWilson May 3 '18 at 15:50
  • Yes it's in Drupal8. See this link for demo files.fm/u/5fcyr5xd – Ajay Reddy May 3 '18 at 16:19
  • Yes, open/close works in Drupal8. – Ajay Reddy May 3 '18 at 16:26
1

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;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.