Previously, an SDC component could be placed inside a form's slot but cound not itself act as a form element.
ComponentElement now implements FormElementInterface and is registered as #[FormElement('component')], so #type: component elements participate in form processing (input handling, validation, value collection) alongside core form elements.
The element's #name and #required are exposed to the component's Twig template under a form_state prop, so the component can render its own <input> using the values supplied by the Form API. A no-op valueCallback() is provided so the Form API falls back to #default_value / #value.
The following standard form properties are supported on #type: component:
#default_value#element_validate#required#value
PHP-only properties (#process, #after_build, #value_callback, #ajax) are not available.
This does not override or replace existing core form elements. It allows new form elements to be defined as SDC components alongside them.
Before
#type: component was a render element only. Defining a form input backed by a component required a custom form element class.
After
A component can be used directly as a form element:
$form['my_field'] = [
'#type' => 'component',
'#component' => 'my_theme:input',
'#default_value' => 'hello',
'#required' => TRUE,
'#element_validate' => [[$this, 'customValidator']],
];
The component's Twig template reads form_state:
{% set input_attributes = create_attribute({
type: 'text',
name: form_state.value.name,
id: id|default('my-sdc-text-field-' ~ random()),
value: form_state.value.value,
}) %}
{% if form_state.value.required %}
{% set input_attributes = input_attributes.setAttribute('required', true) %}
{% endif %}
<div{{ attributes }}>
<label class="form-label" for="{{ input_attributes.id }}">
{{ label }}
</label>
<input{{ input_attributes }}>
</div>
Impact on Themers and Module developers
Themers can define form element as SDC components, making it easier to implement design-system controls (e.g. a Bootstrap switch) without writing a custom form element class. Existing usage of #type: component outside forms is unchanged.