I created a custom module that contains a form with select element I tried to disable the first option like this, but failed to get it work

'#options' => $terms,
                '#empty_option' => '- Select category -',
                '#empty_value' => 'none',
                '#disabled_values' => array('none'),

How could this be achieved without removing the option?


There is a contrib module that can help: Form Options Attributes

This module adds the ability to specify attributes for individual options on Drupal Form API elements of the types: select, checkboxes, and radios.

Also Jaime Calvo's answer about writing:

['#options']['my disabled option'] = [];

Doesn't really create a disabled option, but an empty optgroup.


Drupal by default doesn't allow for this, so you'll need to do two things:

  1. Override theme_select()
  2. Create your own callback the create the options
  3. Change the way you define your select options in your form definition

Overriding theme_select():

function THEME_select($variables) {
  $element = $variables['element'];
  element_set_attributes($element, array('id', 'name', 'size'));
  _form_set_class($element, array('form-select'));

  return '<select' . drupal_attributes($element['#attributes']) . '>' . custom_form_select_options($element) . '</select>';

Create your own callback the create the options:

function custom_form_select_options($element, $choices = NULL) {
  if (!isset($choices)) {
    $choices = $element['#options'];
  // array_key_exists() accommodates the rare event where $element['#value'] is NULL.
  // isset() fails in this situation.
  $value_valid = isset($element['#value']) || array_key_exists('#value', $element);
  $value_is_array = $value_valid && is_array($element['#value']);
  $options = '';
  foreach ($choices as $key => $choice) {
    if (is_array($choice) && !isset($choice['data'])) {
      $options .= '<optgroup label="' . check_plain($key) . '">';
      $options .= form_select_options($element, $choice);
      $options .= '</optgroup>';
    elseif (is_object($choice)) {
      $options .= form_select_options($element, $choice->option);
    else {
      $key = (string) $key;
      if ($value_valid && (!$value_is_array && (string) $element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) {
        $selected = ' selected="selected"';
      else {
        $selected = '';
      $options .= '<option value="' . check_plain($key) . '"' . $selected;
      if(is_array($choice) && isset($choice['disabled']) && $choice['disabled'])
          $options .= ' disabled';
      $choice = is_array($choice) && isset($choice['data']) ? $choice['data'] : $choice;
      $options .= '>' . check_plain($choice) . '</option>';
  return $options;

Change the way you define your select options in your form definition. Turn the option into an array with two keys:

  1. data: The display value of the element
  2. disabled: A boolean indicating whether to disable the element


$form['select'] = array(
  '#title' => t('Pick something'),
  '#type' => 'select',
  '#options' => array(
    'yes' => array('data' => t('Yes'), 'disabled' => TRUE),
    'no' => t('No'),
  • The function THEME_select() and THEME_form_select_options() override by theme. That mean if you write a module, you need override theme too. I think, you can define method process of element select. Same with my problem is here. – MrD Feb 16 '17 at 2:36
  • THEME_form_select_options() was named incorrectly. I have updated my code. – Jaypan Feb 16 '17 at 2:40
  • Your way is correctly. I just note, if you just write in your module. You can write once use everywhere(when you change theme, you don't need copy and override function THEME_select() ). – MrD Feb 16 '17 at 2:47

I prefer in this case use a single line of jQuery.

$("select option:first-child").attr("disabled", "true");

It adds the disabled attribute :

<option value="disabled_options" disabled="disabled">-- choice : --</option>

I would have preferred to do it with formApi but I think this is too much code for a basic thing.


If you just set an empty array as value the option will be disabled.

['#options']['my disabled option'] = [];

this option will get the name, 'my disabled option' and will be disabled.

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.