Skip to main content

Show elements with form #states when values do not match

An article from ComputerMinds - Building with Drupal in the UK since 2005
17th Jan 2017

James Williams

Senior Developer
James Williams
Hey, you seem to look at this article a lot! Why not Bookmark this article so you can find it easily in the future?

I've previously written about dynamic forms in Drupal, using #states to show or hide input boxes depending on other inputs. Since then, Drupal 7 and 8 have both got the ability to combine conditions with OR and XOR operators. This makes it possible to apply changes when a form element's value does not equal something, which is not obvious at all. It's easy to show something when a value does match. This example shows a text input box for specifying which colour is your favourite when you chose 'Other' from a dropdown list of favourite colours.


$form['other_favorite'] = [
  '#type' => 'textfield',
  '#title' => t('Please specify...'),
  '#states' => [
    'visible' => [   // action to take.
      ':input[name="favorite_color"]' // element to evaluate condition on
        => ['value' => 'Other'],  // condition
    ],
  ],
];

But there's no 'opposite' of the value condition, e.g. to show an element when a text box has anything other than the original value in it. Using the 'XOR' condition (which only passes when some conditions are passed, but not all of them), you can combine the value condition with something that will always pass, in order to simulate it instead. Something like this, which shows a checkbox to confirm a change when you enter anything other than your previous favourite food:


$form['confirm_change'] = [
  '#type' => 'checkbox',
  '#title' => t('Yes, I really have changed my mind'),
  // Use XOR so that current_pass element only shows if the email
  // address is not the existing value, and is visible. States cannot
  // check for a value not being something, but by using XOR with a
  // condition that should always be true (i.e. the latter one), this
  // will work. Note the extra level of arrays that is required for
  // using the XOR operator.
  '#states' => [
    'visible' => [
      [':input[name="favorite_food"]' => [
        'value' => $original_favorite_food,
      ]],
      'xor',
      [':input[name="favorite_food"]' => [
        // The checked property on a text input box will always come
        // out false.
        'checked' => FALSE,
      ]],
    ],
  ],
];

Hopefully the comments in that snippet make sense, but essentially it's about picking a second condition that will always pass, so that the combination only passes when the first condition fails. So in this case, whenever the value does not equal the original value. By the way, you can do much more than just show or hide form elements, for example, enabling or disabling - see the full list.

Hi, thanks for reading

ComputerMinds are the UK’s Drupal specialists with offices in Bristol and Coventry. We offer a range of Drupal services including Consultancy, Development, Training and Support. Whatever your Drupal problem, we can help.