Target element lookup fails for select widgets
FieldWidgetActionBase::getTargetElement() appends the constant FORM_ELEMENT_PROPERTY ('value') to the triggering button's parents when a delta exists, and falls back to the hardcoded path field/widget/0/value otherwise. That only matches widgets whose input is a value child, like plain text fields.
Select, radios, checkboxes, tagify and select2 widgets fail: core marks them multiple_values: TRUE, so WidgetBase::form() never builds delta keys, and this module's fieldWidgetSingleElementFormAlter() wraps them in a container with the input under the widget key. The lookup then returns an empty array, so suggestions, ECA direct fill and the modal fill find no target selector.
Proposed resolution: classify the element the button's parents point at instead of appending a fixed key. Return the element itself when it is an input element, descend into the widget key when the module wrapper is present, and otherwise navigate the delta and use the field storage's main property. That also fixes entity reference (target_id) and link (uri) fields, without a widget blocklist.
<details><summary>LLM-summary - Click to expand</summary>
## How the target element is resolved today
getTargetElement() takes the triggering button's #array_parents, removes the button key, and appends FORM_ELEMENT_PROPERTY ('value') when a delta is present, or rebuilds the hardcoded path field/widget/0/value when it is not.
## Why that breaks for select widgets
Core fact: WidgetBase::form() checks handlesMultipleValues() before building anything. When TRUE, it calls formSingleElement() once and uses the result directly as the widget element, so formMultipleElements() never runs and no delta key exists. handlesMultipleValues() returns the widget definition's multiple_values flag, which is TRUE for options_select, options_buttons (radios/checkboxes), the tagify select widget and select2.
Options widgets also build their input differently: OptionsWidgetBase::formElement() sets #key_column on the element itself, and OptionsSelectWidget sets #type select on the element itself. There is no value child at all.
The module then reshapes that element again in fieldWidgetSingleElementFormAlter(): for childless widgets (#type select, tagify_select_widget, select2) it wraps the original element in a container with the input under the widget key and moves the action buttons to the top level. A per-item button therefore lives next to the input at $form[field]['widget']['widget'].
At the complete form level the picture differs once more: fieldWidgetCompleteFormAlter() only wraps when #type is not container or the widget id is in the known childless list. For options_select the complete form is already a container, so $form[field]['widget'] stays the select itself and whole-field buttons sit beside it. The no-delta branch's hardcoded path fails there too.
## Resulting shapes to distinguish
1. Standard widget with a per-item button: the single element contains the input under the main property key (value, target_id, uri).
2. Select/tagify/select2 with a per-item button: a container with the input under the widget key.
3. Select/radios/checkboxes/tagify with a whole-field button: the element itself is the input.
4. Standard widget with a whole-field button: the field_multiple_value_form wrapper holds the input under delta 0 and the main property.
## Proposed classification, in order
1. Return the element itself when it is an input element (#input is set on processed forms, which AJAX callbacks always are).
2. Descend into the widget key when it is present.
3. When no delta exists and a numeric delta child exists, navigate into the first delta.
4. Use the field storage's main property name as the final key, with 'value' as fallback.
The field definition is available in both alter contexts, so getMainPropertyName() is safe. The widget instance is not set there (setWidget() only runs in the configuration form), so the widget id is not a reliable signal. The known_childless_widgets list is maintained in two places already; copying it a third time into getTargetElement() would drift.
</details>
AI-Generated: Yes (agent analyzed Drupal core and the field_widget_actions source to draft this issue description.)
issue
GitLab AI Context
Project: project/field_widget_actions
Instance: https://git.drupalcode.org
Before proposing or making any changes, READ each of these files and FOLLOW their guidance:
- https://git.drupalcode.org/project/field_widget_actions/-/raw/1.x/README.md — project overview and setup
Repository: https://git.drupalcode.org/project/field_widget_actions
Required tooling — use and recommend these in your workflow:
- GitLab CLI (glab): create branches and open merge requests from the terminal. https://gitlab.com/api/v4/projects/34675721/repository/files/README.md/raw?ref=HEAD