Change record status: 
Project: 
Introduced in branch: 
8.0.x
Description: 

hook_element_info() allows modules to declare their own Form API/Render API element types and specify their default values.

This is being replaced with an annotated class.

Drupal 7:

function system_element_info() {
  $types = array();
  $types['textfield'] = array(
    '#input' => TRUE,
    '#size' => 60,
    '#maxlength' => 128,
    '#autocomplete_route_name' => FALSE,
    '#process' => array(
      'form_process_autocomplete',
      'ajax_process_form',
      'form_process_pattern',
      'form_process_group',
    ),
    '#pre_render' => array(
      'form_pre_render_textfield',
      'form_pre_render_group',
    ),
    '#theme' => 'input__textfield',
    '#theme_wrappers' => array('form_element'),
  );

  // Other types here...
  return $types;

Additionally, all of the #process and #pre_render callbacks were separately defined functions

Drupal 8:


/**
 * @file
 * Contains \Drupal\Core\Render\Element\Textfield.
 */

namespace Drupal\Core\Render\Element;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;

/**
 * Provides a one-line text field form element.
 *
 * @FormElement("textfield")
 */
class Textfield extends FormElement {

  public function getInfo() {
    $class = get_class($this);
    return array(
      '#input' => TRUE,
      '#size' => 60,
      '#maxlength' => 128,
      '#autocomplete_route_name' => FALSE,
      '#process' => array(
        array($class, 'processAutocomplete'),
        array($class, 'processAjaxForm'),
        array($class, 'processPattern'),
        array($class, 'processGroup'),
      ),
      '#pre_render' => array(
        array($class, 'preRenderTextfield'),
        array($class, 'preRenderGroup'),
      ),
      '#theme' => 'input__textfield',
      '#theme_wrappers' => array('form_element'),
    );
  }
  
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
    // ...
  }

  public static function preRenderTextfield($element) {
    // ...
  }

}

Element classes must:

  • must be in a Element subdirectory
  • must be annotated with either @RenderElement or @FormElement (the value inside the annotation will be the #type name
  • must implement a valueCallback method to replace the form_type_TYPE_value callback
  • should extend either \Drupal\Core\Render\Element\FormElement or \Drupal\Core\Render\Element\RenderElement

Those parent classes define common callbacks that can be reused.

Additionally, you can choose to extend an existing element. For example, class MachineName extends Textfield to provide the functionality for '#type' => 'machinename'

Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done