I have a textfield element (named 'bus_station'), which holds a bus station name.

I am looking for a way to create a custom 'bus_station' element (possibly extending Textfield class), which would:

  • Still expect a text input in form of bus station name (and retain it during $form_state->setRebuild() and show it to user), but
  • In $form_value, after form submit, either provide a FALSE (custom code in Element definition doesn't recognize input as a station) or TRUE (it does recognize a station)? Or Entity ID (ID of a matched bus station) and/or NULL (no match)?

1 Answer 1


This can be done via Form API callback implementation:

Inside module/src/Element/ElementClass.php, in public function getInfo() {} define a callback, e.g. processMyElement under '#process' key:

public function getInfo() {
  $class = static::class;
  return [
    // [...] Some other definitions.
    '#process' => [
      [$class, 'processMyElement'],

And then perform two complementary operations.

(1) Process the user input and return a value which will be provided in the '#form_state' values in valueCallback() method:

public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
  $output = parent::valueCallback($element, $input, $form_state);
  if ($input == 'SOMETHING') {
    $output = 'SOMETHING_ELSE';
  return $output;

(2) And vice versa, in the processMyElement() method return the original value:

public static function processMyElement(&$element, FormStateInterface $form_state, &$complete_form) {
  if ($element['#value'] == 'SOMETHING_ELSE') {
    $element['#value'] = 'SOMETHING';
  return $element;

Usage example

I have used this to extend Drupal\Core\Render\Element\Textfield class in combination with JS Storage Complete. That gives me Autocomplete (without need for a callback URL). This autocomplete returns Entity ID obtained via entity load based on unique label inside valueCallback() method, but user is still presented with its text input (obtained by returning $entity->label() inside processMyElement() method).

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.