Backend Development - Field Widgets

In the previous topic, we created a custom Field Type, which defined how data is stored and structured. Now we move to the next layer of the field system: Field Widgets.

If a field type defines the data model, a field widget defines how users input that data.

Widgets are responsible for:

  • Rendering form elements
  • Handling input structure
  • Providing configuration options
  • Integrating with validation

This topic continues the learning-by-building approach using the same weeklydrupal_demo module and the rating field type we created earlier.

By the end of this article, you will understand:

  • What a field widget is
  • How widgets connect to field types
  • How to create a custom widget plugin
  • How Drupal builds widget form elements
  • When to create a custom widget

1. What Is a Field Widget

A field widget controls how a field appears on entity edit forms.

For example:

  • A text field may use a text input or textarea
  • A boolean field may use a checkbox
  • An entity reference field may use autocomplete

The same field type can have multiple widgets.

In simple terms:

Field type = how data is stored
Field widget = how data is entered


2. Where Field Widgets Live

Widgets are plugin classes located in:

src/Plugin/Field/FieldWidget

Drupal discovers them using annotations.


3. Creating a Widget for the Rating Field

We will create a custom widget for our rating field type.

File path

weeklydrupal_demo/src/Plugin/Field/FieldWidget/RatingWidget.php

Code

<?php

namespace Drupal\weeklydrupal_demo\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Plugin implementation of the 'rating_widget' widget.
 *
 * @FieldWidget(
 *   id = "rating_widget",
 *   label = @Translation("Rating Select"),
 *   field_types = {
 *     "rating"
 *   }
 * )
 */
class RatingWidget extends WidgetBase {

  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

    $value = isset($items[$delta]->value) ? $items[$delta]->value : NULL;

    $element['value'] = [
      '#type' => 'select',
      '#title' => $this->t('Rating'),
      '#options' => [
        1 => '1',
        2 => '2',
        3 => '3',
        4 => '4',
        5 => '5',
      ],
      '#default_value' => $value,
    ];

    return $element;
  }

}

4. Understanding the Annotation

@FieldWidget(
  id = "rating_widget",
  label = @Translation("Rating Select"),
  field_types = { "rating" }
)

Explanation:

  • id – Machine name of the widget
  • label – Displayed in field UI
  • field_types – Which field types this widget supports

This connects the widget to the rating field type.


5. The formElement() Method

public function formElement(...)

This method:

  • Builds the form element
  • Receives the current field values
  • Returns a render array

Drupal automatically integrates this into the entity edit form.


6. Understanding $items and $delta

  • $items contains field values
  • $delta represents the index when fields allow multiple values

For multi-value fields, Drupal calls formElement() once per item.


7. How Drupal Uses the Widget

When editing an entity:

  1. Drupal loads field definitions
  2. Finds the selected widget
  3. Calls formElement()
  4. Merges returned render array into the form

The widget does not save data directly. Drupal handles storage.


8. Widget Configuration

Widgets can provide configuration settings.

Example:

public static function defaultSettings() {
  return [
    'max_rating' => 5,
  ] + parent::defaultSettings();
}

You can then use this setting inside formElement().

This allows widgets to be flexible and reusable.


9. When to Create a Custom Widget

Create a custom widget when:

  • Default widgets do not match UX requirements
  • You need specialized input structure
  • You need controlled input options
  • Validation depends on structured input

Do not create a custom widget just for styling. That belongs in themes.


10. Common Mistakes to Avoid

  • Mixing storage logic inside the widget
  • Hardcoding values that should be configurable
  • Ignoring multi-value behavior
  • Not returning the correct render array structure

Widgets should focus only on input.


11. Learning by Building: weeklydrupal_demo

Our module now includes:

  • Custom field type
  • Custom field widget
  • Typed data definitions
  • Schema integration

Next we will complete the field system by building a Field Formatter.


12. Why Field Widgets Matter

Understanding field widgets helps you:

  • Control editorial experience
  • Build structured input systems
  • Improve usability without breaking storage
  • Separate data model from UI

This separation is central to Drupal architecture.