form #type => checkboxes with zero / empty option value I am building something which uses a form element with '#type' =&gt; 'checkboxes'.

I want this to be reusable, so it should accept anything as option values that works as a PHP array key (integers and non-integer strings).

$form['checkboxes'] = [
  '#type' =&gt; 'checkboxes',
  '#options' =&gt; [
    0 =&gt; 'zero',
    '' =&gt; 'empty string',
    ' ' =&gt; 'space',
    'other' =&gt; 'Other',
  ],
];


However there seems to be a problem with values 0 (zero) and '' (empty string).

Even when the checkboxes for '' or 0 are checked, the values are gone in the $element['#value'] array, e.g. when checking with a custom '#element_validate' callback.

$element['#value'] === [
  # '' and 0 are gone, even if they were checked.
  ' ' =&gt; ' ',
  'other' =&gt; 'other',
];


Interestingly, the $_POST still contains the values, with an interesting twist, where space and empty string behave like array insertion via []. I suppose this is due to the way POST data is sent.

$_POST['checkboxes'] === [
  0 =&gt; '0',
  1 =&gt; '',
  2 =&gt; ' ',
  'other' =&gt; 'other',
];


I can imagine why all of this happens, but is there a workaround or solution?

EDIT: The previous version of the code snippet was misleading, sorry. I had mixed up $_POST and the original '#options' array.
I managed to prevent this problem by adding an '#element_validate' handler on the checkboxes element.

The code below is a simplified version of what I did, up to you to fine-tune.

$element['#element_validate'][] = '_MYMODULE_checkboxes_validate';

function _MYMODULE_checkboxes_validate(array &amp;$element, array &amp;$form_state) {

  // The form value already has the format $[$id] = $id, mostly.
  // However, if trim($id) === '', the array key will be an integer increment.
  $value = $element['#value'];

  // Make sure it has the expected format.
  if (!is_array($value) || [] === $value) {
    $ids = [];
  }
  else {
    // Get rid of integer keys for empty-ish string ids.
    $ids = array_combine($value, $value);
  }

  // Remove dangling * =&gt; 0 entries.
  form_set_value($element, $ids, $form_state);
}


Note: If you have the value_is module installed, empty-ish values will always be unset, thanks to _value_is_disabled_options_value_callback().