When to Use
Use this guide when adding action buttons to field widgets on entity edit forms.
The field_widget_actions module is an AI-agnostic framework for attaching action buttons to field widgets on entity forms. Other modules provide the actual plugins.
Decision
| Situation |
Choose |
Why |
| Simple action button |
FieldWidgetActionBase |
Direct action on click |
| Multi-step interaction |
FieldWidgetFormActionBase |
Modal dialog with form |
| Fill a text input |
FillSimpleFieldCommand |
Standard AJAX command |
| Fill CKEditor |
FillEditorCommand |
CKEditor-specific AJAX command |
| Deploy via recipe |
setComponentThirdPartySetting config action |
Declarative recipe config |
Plugin System
use Drupal\field_widget_actions\Attribute\FieldWidgetAction;
#[FieldWidgetAction(
id: 'my_action',
label: new TranslatableMarkup('AI Suggest'),
widget_types: ['text_textarea'],
field_types: ['text_long'],
category: new TranslatableMarkup('AI'),
multiple: TRUE, // Button per delta
)]
class MyAction extends FieldWidgetActionBase {
public function isAvailable(): bool {
return $this->providerManager->hasProvidersForOperationType('chat');
}
public function singleElementFormAlter(array &$form, FormStateInterface $form_state, array $context = []) {
parent::singleElementFormAlter($form, $form_state, $context);
// Parent adds the action button.
}
}
For multi-step interactions, extend FieldWidgetFormActionBase:
public function buildModalForm(array $form, FormStateInterface $form_state, ?ContentEntityInterface $entity): array {
$form['selection'] = ['#type' => 'radios', '#options' => [...]];
return $form;
}
protected function submitModalFormFillFields(array $form, FormStateInterface $form_state, AjaxResponse $response): AjaxResponse {
$response->addCommand(new FillSimpleFieldCommand($selector, $value));
return $response;
}
Ajax Commands
| Command |
Purpose |
FillSimpleFieldCommand |
Fill an input/textarea |
FillEditorCommand |
Fill a CKEditor instance |
Config Action for Recipes
| Method |
Purpose |
returnSuggestions($suggestions, $selector) |
Returns an AjaxResponse showing suggestions in a modal dialog |
getSuggestionsTarget($form, $form_state) |
Returns the CSS selector for the target field element |
buildEntity($form, $form_state) |
Reconstructs the entity from form state (for context-aware actions) |
processWidgetWithGroup($form, $form_state, $context) |
Processes widget actions grouped by field |
config:
actions:
core.entity_form_display.node.article.default:
setComponentThirdPartySetting:
component: body
settings:
bc6795f3-uuid:
plugin_id: prompt_content_suggestion
enabled: true
settings:
prompt: 'Suggest content'
| Method |
Purpose |
returnSuggestions($suggestions, $selector) |
Returns an AjaxResponse showing suggestions in a modal dialog |
getSuggestionsTarget($form, $form_state) |
Returns the CSS selector for the target field element |
buildEntity($form, $form_state) |
Reconstructs the entity from form state (for context-aware actions) |
processWidgetWithGroup($form, $form_state, $context) |
Processes widget actions grouped by field |
ImageAltTextActionButtonTrait
Trait for image alt text actions that conditionally shows the button only when an image is uploaded. Uses Drupal #states visibility to hide the button until a file is present in the image widget.
| Method |
Purpose |
getAllowedFieldWidgetActions($widget_type, $field_type) |
Returns plugins applicable to the given widget/field type combination |
getFieldWidgetActionFormDefinitions($widget_type, $field_type) |
Returns form element definitions for the "manage form display" settings |
Override in your plugin for non-standard fields:
- Default:
'value'
- Entity reference:
'target_id'
- Image alt:
'alt'
Common Mistakes
| Mistake |
Why it's wrong |
Not implementing isAvailable() |
FieldWidgetActionBase::isAvailable() defaults to TRUE — the button shows even when no provider is configured, unless you override it (e.g., to check hasProvidersForOperationType()) |
Using FillEditorCommand for a plain textarea |
FillEditorCommand is CKEditor-specific; use FillSimpleFieldCommand for standard inputs |
See Also