Create a custom field widget
This documentation needs work. See "Help improve this page" in the sidebar.
Field widgets are used to render the field inside forms. Field widgets are defined as plugins, so it's a good idea to familiarize yourself with the Plugin API before diving into writing a new field type.
To create a field widget in Drupal 8 you need a class with the FieldWidget annotation.
The location of the field widget class should be /[MODULE_NAME]/src/Plugin/Field/FieldWidget/
. For example, /foo/src/Plugin/Field/FieldWidget/BarWidget.php
.
The namespace of that class should be \Drupal\[MODULE_NAME]\Plugin\Field\FieldWidget
. For example, \Drupal\foo\Plugin\Field\FieldWidget
.
The annotation above the class should include a unique id, a label and an array of ids of field types that this widget can handle.
/**
* A widget bar.
*
* @FieldWidget(
* id = "bar",
* label = @Translation("Bar widget"),
* field_types = {
* "baz",
* "string"
* }
* )
*/
The class needs to implement the WidgetInterface interface. And can extend the WidgetBase class for common implementation of the interface. The only required method to implement is ::formElement()
which should return the actual form elements that represent your widget.
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
//...
class BarWidget extends WidgetBase {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element += [
// Add to the element render array passed in.
// See WidgetInterface::formElement().
];
return ['value' => $element];
}
}
Widget Settings
If your widget needs additional settings, there are three steps required to achieve this:
- Override PluginSettingsBase::defaultSettings() in order to set the defaults
- Create the configuration schema for the settings you've created
- Create a form to allow users to change the settings
Step 1: Override PluginSettingsBase::defaultSettings() in order to set the defaults
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
// Create the custom setting 'size', and
// assign a default value of 60
'size' => 60,
] + parent::defaultSettings();
}
Step 2: Create the configuration schema for the settings you've created
Configuration schema goes in the following file:
/[MODULE_NAME]/config/schema/[MODULE_NAME].schema.yml
In this file, you will describe the data type(s) of the setting(s) you've introduced in defaultSettings():
Step 1 created a setting named 'size', that stores an integer value. The schema for this would look like the following:
field.widget.settings.[WIDGET ID]:
type: mapping
label: 'WIDGET NAME widget settings'
mapping:
size:
type: integer
label: 'Size'
Step 3 - Create a form to allow users to change the settings
The form to allow for users to change the values for the settings is created by overriding WidgetBase::settingsForm()
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$element['size'] = [
'#type' => 'number',
'#title' => $this->t('Size of textfield'),
'#default_value' => $this->getSetting('size'),
'#required' => TRUE,
'#min' => 1,
];
return $element;
}
You can also list the selected settings in the summary for the widget as follows:
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = [];
$summary[] = $this->t('Textfield size: @size', ['@size' => $this->getSetting('size')]);
return $summary;
}
You can use the getSetting() method of the class to retrieve the setting, for use in the widget:
class BarWidget extends WidgetBase implements WidgetInterface {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element['value'] = $element + [
'#type' => 'textfield',
'#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
'#size' => $this->getSetting('size'),
];
return $element;
}
}
Example Widget
The TextWidget from the field_example module under the examples project:
namespace Drupal\field_example\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Plugin implementation of the 'field_example_text' widget.
*
* @FieldWidget(
* id = "field_example_text",
* module = "field_example",
* label = @Translation("RGB value as #ffffff"),
* field_types = {
* "field_example_rgb"
* }
* )
*/
class TextWidget extends WidgetBase {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$value = isset($items[$delta]->value) ? $items[$delta]->value : '';
$element += [
'#type' => 'textfield',
'#default_value' => $value,
'#size' => 7,
'#maxlength' => 7,
'#element_validate' => [
[static::class, 'validate'],
],
];
return ['value' => $element];
}
/**
* Validate the color text field.
*/
public static function validate($element, FormStateInterface $form_state) {
$value = $element['#value'];
if (strlen($value) == 0) {
$form_state->setValueForElement($element, '');
return;
}
if (!preg_match('/^#([a-f0-9]{6})$/iD', strtolower($value))) {
$form_state->setError($element, t("Color must be a 6-digit hexadecimal value, suitable for CSS."));
}
}
}
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion