With the release of Drupal 8, Drupal has finally entered into the realm of HTML5. The Form API now allows utilization of HTML5 input elements out of the box. These include the following element types:
tel
email
number
date
url
search
range
This allows your forms in Drupal to leverage native device input methods along with native validation support.
This recipe will walk you through adding elements to a Drupal form. You will need to have a custom form implemented through a module, such as the one created in the Creating a form section.
form
element definition of the tel
type to your buildForm
method:$form['phone'] = array( '#type' => 'tel', '#title' => t('Phone'), );
form
element definition of the email
type to your buildForm
method. It will validate the format of e-mail addresses in the Form API:$form['email'] = array( '#type' => 'email', '#title' => t('Email'), );
form
element definition of the number type to your buildForm
method. It will validate the range and format of the number:$form['integer'] = array( '#type' => 'number', '#title' => t('Some integer'), // The increment or decrement amount '#step' => 1, // Miminum allowed value '#min' => 0, // Maxmimum allowed value '#max' => 100, );
form
element definition of the date
type to your buildForm
method. You can also pass the #date_date_format
option to alter the format used by the input:$form['date'] = array( '#type' => 'date', '#title' => t('Date'), '#date_date_format' => 'Y-m-d', );
form
element definition of the url
type to your buildForm
method. The element has a validator to check the format of the URL:$form['website'] = array( '#type' => 'url', '#title' => t('Website'), );
form
element definition of the search
type to your buildForm
method. You can specify a route name that the search field will query for autocomplete options:$form['search'] = array( '#type' => 'search', '#title' => t('Search'), '#autocomplete_route_name' => FALSE, );
range
input, you need to add a new form
element definition of the range
type to your buildForm
method. It is an extension of the number element and accepts a min
, max
, and step
property to control the values of the range input:$form['range'] = array( '#type' => 'range', '#title' => t('Range'), '#min' => 0, '#max' => 100, '#step' => 1, );
Each type references an extended class of DrupalCoreRenderElementFormElement
. It provides the element's definition and additional functions. Each element defines a prerender
method in the class that defines the input
type attribute along with other additional attributes.
Each input defines its theme as input__TYPE
, allowing you to copy the input.html.twig
base to input.TYPE.html.twig
for templating. The template then parses the attributes and renders the HTML.
Some elements, such as e-mails, provide validators for the element itself. The e-mail element defines the validateEmail
method. Here is an example of the code from DrupalCoreRenderElementEmail::valdateEmail
:
/** * Form element validation handler for #type 'email'. * * Note that #maxlength and #required is validated by _form_validate() already. */ public static function validateEmail(&$element, FormStateInterface $form_state, &$complete_form) { $value = trim($element['#value']); $form_state->setValueForElement($element, $value); if ($value !== '' && !Drupal::service('email.validator')->isValid($value)) { $form_state->setError($element, t('The email address %mail is not valid.', array('%mail' => $value))); } }
This code will be executed on form submission and validate the provider's e-mail. It does this by taking the current value and trimming any whitespaces and using the form state object to update the value. The email.validator
service is invoked to validate the e-mail. If this method returns false
, the form state is invoked to mark the element as the one that has an error. If the element has an error, the form builder will prevent form submission, returning the user to the form to fix the value.
Elements are provided through Drupal's plugin system and are explored in detail in the next section.
Elements can have their own unique properties along with individual validation methods. At the time of writing, the Drupal 8 Form Reference table is incomplete and does not highlight these new elements nor their properties. However, the classes can be examined and the definition method can be read to learn about the properties of each element. These classes are under the DrupalCoreRenderElement
namespace located in /core/lib/Drupal/Core/
Render/Element
:
Each element used in the Form API extends the DrupalCoreRenderElementFormElement
class, which is a plugin. Modules can provide new element types by adding classes to their Plugins/Element namespace. Refer to Chapter 7, Plug and Play with Plugins for more information on how to implement a plugin.