Breaking: #97330 - FormEngine element classes must create label or legend¶
See forge#97330
Description¶
When editing records in the backend, the FormEngine
class structure located
within EXT:backend/Classes/Form/
handles the generation of the editing view.
A change has been applied related to the rendering of single field labels, which is no longer done automatically by "container" classes: Single elements have to create the label themselves.
Extension that add own elements to FormEngine must be adapted, otherwise the element label is no longer rendered.
Impact¶
When the required changes are not applied to custom FormEngine element classes, the value of the TCA "label" property is not rendered.
Affected installations¶
Instances with custom FormEngine elements are affected. Custom elements need to be
registered to the FormEngine's NodeFactory
, candidates are found by looking at
the $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']
array (for instance
using the System > Configuration backend module provided by
EXT:lowlevel). Classes registered using the sub keys nodeRegistry
and
nodeResolver
may be affected. The extension scanner does not find
affected classes.
Migration¶
Custom elements must take care of creating a <label>
or <legend>
tag on their own: If the element creates an <input>
, or <select>
tag,
the <label>
should have a for
attribute that points to a field having
an id
attribute. This is important especially for accessibility. When no such
target element exists, a <legend>
embedded in a <fieldset>
can be used.
There are two helper methods in
\TYPO3\CMS\Backend\Form\Element\AbstractFormElement
to help with this:
renderLabel()
and wrapWithFieldsetAndLegend()
.
In practice, an element having an <input>
, or <select>
field should
essentially look like this:
$resultArray = $this->initializeResultArray();
// Next line is only needed for extensions that need to keep TYPO3 v12 compatibility
$resultArray['labelHasBeenHandled'] = true;
$fieldId = StringUtility::getUniqueId('formengine-input-');
$html = [];
$html[] = $this->renderLabel($fieldId);
$html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
$html[] = '<div class="form-wizards-wrap">';
$html[] = '<div class="form-wizards-element">';
$html[] = '<div class="form-control-wrap">';
$html[] = '<input class="form-control" id="' . htmlspecialchars($fieldId) . '" value="..." type="text">';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$resultArray['html'] = implode(LF, $html);
return $resultArray;
The renderLabel()
is a helper method to generate a <label>
tag with a
for
attribute, and the same fieldId is used as id
attribute in the
<input>
field to connect <label>
and <input>
with each other.
If there is no such field, a <legend>
tag should be used:
$resultArray = $this->initializeResultArray();
// Next line is only needed for extensions that need to keep TYPO3 v12 compatibility
$resultArray['labelHasBeenHandled'] = true;
$html = [];
$html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
$html[] = '<div class="form-wizards-wrap">';
$html[] = '<div class="form-wizards-element">';
$html[] = '<div class="form-control-wrap">';
$html[] = Some custom element html
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$resultArray['html'] = $this->wrapWithFieldsetAndLegend(implode(LF, $html));
return $resultArray;