From d421f7dc2f4e6f5f5b57aed762859e92f59533f6 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Wed, 27 Jun 2018 16:46:00 +0200
Subject: [PATCH] [FEATURE] Allow TCA description property
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When the site configuration module has been introduced, it came
with a custom functionality to show an additional help text
when editing site records between the field label and the field input.

This useful feature is now changed into a general TCA feature
available everywhere: A new field information node expansion / "wizard"
is added to all form elements, the inline and flex containers: If
the property "description" is set for a TCA column type (same array
level as "label", it will show the value as localized string between
the field label and the input section.

There are three available render types for "wizard a-like" output:
* Field information - text between label+field
* Field control - buttons next to input sections like the link popup button
* Field wizards - clickable stuff below the input section, for example
  the localization state selector
If a field has been set to readOnly=true in TCA, field control and field
wizards do not make sense to render since they are meant to act with the
field value.
The field information node however has only informational character
which is useful for readOnly fields, too. Thus, this node expansion
type is now the only one that is always rendered, even if a field has
been set to readOnly.

Note this patch is fully covered by ext:styleguide (master) to have
examples for all changed elements now using the description property.

Resolves: #85410
Releases: master
Change-Id: Idcfacafa19b8208614b653b8fac22ce47bca3b8f
Reviewed-on: https://review.typo3.org/57397
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Jörg Bösche <typo3@joergboesche.de>
Tested-by: Jörg Bösche <typo3@joergboesche.de>
Reviewed-by: Andreas Wolf <andreas.wolf@typo3.org>
Tested-by: Andreas Wolf <andreas.wolf@typo3.org>
---
 .../Container/FlexFormContainerContainer.php  |  3 +-
 .../Container/FlexFormElementContainer.php    |  5 ++
 .../Container/FlexFormNoTabsContainer.php     | 20 ++++-
 .../Form/Container/FlexFormTabsContainer.php  | 18 ++++-
 .../Form/Container/InlineControlContainer.php | 16 ++++
 .../Classes/Form/Element/CheckboxElement.php  | 15 +++-
 .../Element/CheckboxLabeledToggleElement.php  | 15 +++-
 .../Form/Element/CheckboxToggleElement.php    | 15 +++-
 .../Classes/Form/Element/GroupElement.php     | 20 ++++-
 .../Form/Element/ImageManipulationElement.php | 11 +++
 .../Form/Element/InputColorPickerElement.php  | 20 ++++-
 .../Form/Element/InputDateTimeElement.php     | 20 ++++-
 .../Classes/Form/Element/InputLinkElement.php | 20 ++++-
 .../Classes/Form/Element/InputTextElement.php | 20 ++++-
 .../Classes/Form/Element/NoneElement.php      | 15 +++-
 .../Classes/Form/Element/RadioElement.php     | 77 +++++++++++--------
 .../Form/Element/SelectCheckBoxElement.php    | 15 +++-
 .../SelectMultipleSideBySideElement.php       | 18 ++++-
 .../Form/Element/SelectSingleBoxElement.php   | 15 +++-
 .../Form/Element/SelectSingleElement.php      | 15 +++-
 .../Form/Element/SelectTreeElement.php        | 15 +++-
 .../Classes/Form/Element/TextElement.php      | 20 ++++-
 .../Classes/Form/Element/TextTableElement.php | 20 ++++-
 ...teConfiguration.php => TcaDescription.php} | 18 +++--
 .../backend/Classes/Form/NodeFactory.php      |  3 +
 .../Configuration/SiteConfiguration/site.php  | 17 +---
 .../SiteConfiguration/site_errorhandling.php  | 43 +----------
 .../SiteConfiguration/site_language.php       | 63 +--------------
 typo3/sysext/backend/ext_localconf.php        |  7 --
 ...ture-85410-AllowTCADescriptionProperty.rst | 40 ++++++++++
 .../Classes/Form/Element/RsaInputElement.php  | 20 ++++-
 .../Classes/Form/Element/RichTextElement.php  | 11 +++
 .../Classes/Form/Element/T3editorElement.php  | 11 +++
 33 files changed, 439 insertions(+), 222 deletions(-)
 rename typo3/sysext/backend/Classes/Form/FieldInformation/{SiteConfiguration.php => TcaDescription.php} (58%)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-85410-AllowTCADescriptionProperty.rst

diff --git a/typo3/sysext/backend/Classes/Form/Container/FlexFormContainerContainer.php b/typo3/sysext/backend/Classes/Form/Container/FlexFormContainerContainer.php
index 226a03561088..54ab93a539da 100644
--- a/typo3/sysext/backend/Classes/Form/Container/FlexFormContainerContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/FlexFormContainerContainer.php
@@ -82,6 +82,8 @@ class FlexFormContainerContainer extends AbstractContainer
             $containerTitle = $languageService->sL(trim($flexFormDataStructureArray['title']));
         }
 
+        $resultArray = $this->initializeResultArray();
+
         $html = [];
         $html[] = '<div class="t3-form-field-container-flexsections t3-flex-section t3js-flex-section">';
         $html[] =    '<input class="t3-flex-control t3js-flex-control-action" type="hidden" name="' . htmlspecialchars($actionFieldName) . '" value="" />';
@@ -113,7 +115,6 @@ class FlexFormContainerContainer extends AbstractContainer
         $html[] =    '</div>';
         $html[] = '</div>';
 
-        $resultArray = $this->initializeResultArray();
         $resultArray['html'] = implode(LF, $html);
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $containerContentResult, false);
 
diff --git a/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php b/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
index 87f7b1feb00b..8592857a75b2 100644
--- a/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
@@ -82,6 +82,10 @@ class FlexFormElementContainer extends AbstractContainer
                     'label' => $parameterArray['label'],
                 ];
 
+                if (isset($flexFormFieldArray['description']) && !empty($flexFormFieldArray['description'])) {
+                    $fakeParameterArray['fieldConf']['description'] = $flexFormFieldArray['description'];
+                }
+
                 $alertMsgOnChange = '';
                 if (isset($fakeParameterArray['fieldConf']['onChange']) && $fakeParameterArray['fieldConf']['onChange'] === 'reload') {
                     if ($this->getBackendUserAuthentication()->jsConfirmation(JsConfirmation::TYPE_CHANGE)) {
@@ -138,6 +142,7 @@ class FlexFormElementContainer extends AbstractContainer
 
                 // Possible line breaks in the label through xml: \n => <br/>, usage of nl2br() not possible, so it's done through str_replace (?!)
                 $processedTitle = str_replace('\\n', '<br />', htmlspecialchars($fakeParameterArray['fieldConf']['label']));
+
                 $html = [];
                 $html[] = '<div class="form-section">';
                 $html[] =    '<div class="form-group t3js-formengine-palette-field t3js-formengine-validation-marker">';
diff --git a/typo3/sysext/backend/Classes/Form/Container/FlexFormNoTabsContainer.php b/typo3/sysext/backend/Classes/Form/Container/FlexFormNoTabsContainer.php
index d4170f803c89..b40ae71387d1 100644
--- a/typo3/sysext/backend/Classes/Form/Container/FlexFormNoTabsContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/FlexFormNoTabsContainer.php
@@ -25,6 +25,17 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class FlexFormNoTabsContainer extends AbstractContainer
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Entry method
      *
@@ -71,7 +82,14 @@ class FlexFormNoTabsContainer extends AbstractContainer
         $options['flexFormFormPrefix'] = '[data][' . $sheetName . '][lDEF]';
         $options['parameterArray'] = $parameterArray;
 
+        $resultArray = $this->initializeResultArray();
+
+        $fieldInformationResult = $this->renderFieldInformation();
+        $resultArray['html'] = '<div>' . $fieldInformationResult['html'] . '</div>';
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         $options['renderType'] = 'flexFormElementContainer';
-        return $this->nodeFactory->create($options)->render();
+        $childResult = $this->nodeFactory->create($options)->render();
+        return $this->mergeChildReturnIntoExistingResult($resultArray, $childResult, true);
     }
 }
diff --git a/typo3/sysext/backend/Classes/Form/Container/FlexFormTabsContainer.php b/typo3/sysext/backend/Classes/Form/Container/FlexFormTabsContainer.php
index 70572dc9c958..df27b14dc4ad 100644
--- a/typo3/sysext/backend/Classes/Form/Container/FlexFormTabsContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/FlexFormTabsContainer.php
@@ -25,6 +25,17 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class FlexFormTabsContainer extends AbstractContainer
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Entry method
      *
@@ -42,6 +53,7 @@ class FlexFormTabsContainer extends AbstractContainer
         $flexFormRowData = $this->data['flexFormRowData'];
 
         $resultArray = $this->initializeResultArray();
+
         $resultArray['requireJsModules'][] = 'TYPO3/CMS/Backend/Tabs';
 
         $domIdPrefix = 'DTM-' . GeneralUtility::shortMD5($this->data['parameterArray']['itemFormElName']);
@@ -94,7 +106,11 @@ class FlexFormTabsContainer extends AbstractContainer
             $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childReturn, false);
         }
 
-        $resultArray['html'] = $this->renderTabMenu($tabElements, $domIdPrefix);
+        $fieldInformationResult = $this->renderFieldInformation();
+        $resultArray['html'] = '<div>' . $fieldInformationResult['html'] . '</div>';
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
+        $resultArray['html'] .= $this->renderTabMenu($tabElements, $domIdPrefix);
         return $resultArray;
     }
 
diff --git a/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php b/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php
index 8a56839ce826..e2ecc5f8f2f2 100644
--- a/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php
@@ -62,6 +62,17 @@ class InlineControlContainer extends AbstractContainer
      */
     protected $requireJsModules = [];
 
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * @var array Default wizards
      */
@@ -270,6 +281,11 @@ class InlineControlContainer extends AbstractContainer
         }
         // Wrap all inline fields of a record with a <div> (like a container)
         $html = '<div class="form-group" id="' . $nameObject . '">';
+
+        $fieldInformationResult = $this->renderFieldInformation();
+        $html .= $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         // Add the level links before all child records:
         if ($config['appearance']['levelLinksPosition'] === 'both' || $config['appearance']['levelLinksPosition'] === 'top') {
             $html .= '<div class="form-group t3js-formengine-validation-marker">' . $levelLinks . $localizationLinks . '</div>';
diff --git a/typo3/sysext/backend/Classes/Form/Element/CheckboxElement.php b/typo3/sysext/backend/Classes/Form/Element/CheckboxElement.php
index cffae653b80e..0f4cda863460 100644
--- a/typo3/sysext/backend/Classes/Form/Element/CheckboxElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/CheckboxElement.php
@@ -30,6 +30,17 @@ class CheckboxElement extends AbstractFormElement
      */
     private $iconRegistry;
 
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -130,9 +141,7 @@ class CheckboxElement extends AbstractFormElement
 
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-        if (!$disabled) {
-            $html[] = $fieldInformationHtml;
-        }
+        $html[] = $fieldInformationHtml;
         $html[] =   '<div class="form-wizards-wrap">';
         $html[] =       '<div class="form-wizards-element">';
         $html[] =           $elementHtml;
diff --git a/typo3/sysext/backend/Classes/Form/Element/CheckboxLabeledToggleElement.php b/typo3/sysext/backend/Classes/Form/Element/CheckboxLabeledToggleElement.php
index a90214aa5c55..adfba81273cc 100644
--- a/typo3/sysext/backend/Classes/Form/Element/CheckboxLabeledToggleElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/CheckboxLabeledToggleElement.php
@@ -29,6 +29,17 @@ class CheckboxLabeledToggleElement extends AbstractFormElement
      */
     private $iconRegistry;
 
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -129,9 +140,7 @@ class CheckboxLabeledToggleElement extends AbstractFormElement
 
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-        if (!$disabled) {
-            $html[] = $fieldInformationHtml;
-        }
+        $html[] = $fieldInformationHtml;
         $html[] =   '<div class="form-wizards-wrap">';
         $html[] =       '<div class="form-wizards-element">';
         $html[] =           $elementHtml;
diff --git a/typo3/sysext/backend/Classes/Form/Element/CheckboxToggleElement.php b/typo3/sysext/backend/Classes/Form/Element/CheckboxToggleElement.php
index 1f079bf8f6af..f3a63dc92d51 100644
--- a/typo3/sysext/backend/Classes/Form/Element/CheckboxToggleElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/CheckboxToggleElement.php
@@ -29,6 +29,17 @@ class CheckboxToggleElement extends AbstractFormElement
      */
     private $iconRegistry;
 
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -129,9 +140,7 @@ class CheckboxToggleElement extends AbstractFormElement
 
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-        if (!$disabled) {
-            $html[] = $fieldInformationHtml;
-        }
+        $html[] = $fieldInformationHtml;
         $html[] =   '<div class="form-wizards-wrap">';
         $html[] =       '<div class="form-wizards-element">';
         $html[] =           $elementHtml;
diff --git a/typo3/sysext/backend/Classes/Form/Element/GroupElement.php b/typo3/sysext/backend/Classes/Form/Element/GroupElement.php
index f8dd6c9be0e7..a425f6ec204a 100644
--- a/typo3/sysext/backend/Classes/Form/Element/GroupElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/GroupElement.php
@@ -27,6 +27,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class GroupElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field controls for this element.
      *
@@ -175,10 +186,15 @@ class GroupElement extends AbstractFormElement
             );
         }
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if (isset($config['readOnly']) && $config['readOnly']) {
             // Return early if element is read only
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<select';
@@ -287,10 +303,6 @@ class GroupElement extends AbstractFormElement
             $selectorAttributes['multiple'] = 'multiple';
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldControlResult = $this->renderFieldControl();
         $fieldControlHtml = $fieldControlResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
diff --git a/typo3/sysext/backend/Classes/Form/Element/ImageManipulationElement.php b/typo3/sysext/backend/Classes/Form/Element/ImageManipulationElement.php
index 07380da8d7b4..1581eceeefe3 100644
--- a/typo3/sysext/backend/Classes/Form/Element/ImageManipulationElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/ImageManipulationElement.php
@@ -78,6 +78,17 @@ class ImageManipulationElement extends AbstractFormElement
         ]
     ];
 
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
diff --git a/typo3/sysext/backend/Classes/Form/Element/InputColorPickerElement.php b/typo3/sysext/backend/Classes/Form/Element/InputColorPickerElement.php
index 85bf99b4303e..1aaee2502155 100644
--- a/typo3/sysext/backend/Classes/Form/Element/InputColorPickerElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/InputColorPickerElement.php
@@ -24,6 +24,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class InputColorPickerElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -69,9 +80,14 @@ class InputColorPickerElement extends AbstractFormElement
         $width = (int)$this->formMaxWidth($size);
         $nullControlNameEscaped = htmlspecialchars('control[active][' . $table . '][' . $row['uid'] . '][' . $fieldName . ']');
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if ($config['readOnly']) {
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
@@ -149,10 +165,6 @@ class InputColorPickerElement extends AbstractFormElement
             $valuePickerHtml[] = '</select>';
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldWizardResult = $this->renderFieldWizard();
         $fieldWizardHtml = $fieldWizardResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
diff --git a/typo3/sysext/backend/Classes/Form/Element/InputDateTimeElement.php b/typo3/sysext/backend/Classes/Form/Element/InputDateTimeElement.php
index bf836517c621..d8ed303c6a5e 100644
--- a/typo3/sysext/backend/Classes/Form/Element/InputDateTimeElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/InputDateTimeElement.php
@@ -25,6 +25,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class InputDateTimeElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -91,11 +102,16 @@ class InputDateTimeElement extends AbstractFormElement
         $size = MathUtility::forceIntegerInRange($config['size'] ?? $defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth);
         $width = (int)$this->formMaxWidth($size);
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if (isset($config['readOnly']) && $config['readOnly']) {
             // Early return for read only fields
             $itemValue = $this->formatValue($format, $itemValue);
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
@@ -160,10 +176,6 @@ class InputDateTimeElement extends AbstractFormElement
             $itemValue = gmdate('c', (int)$itemValue);
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldWizardResult = $this->renderFieldWizard();
         $fieldWizardHtml = $fieldWizardResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
diff --git a/typo3/sysext/backend/Classes/Form/Element/InputLinkElement.php b/typo3/sysext/backend/Classes/Form/Element/InputLinkElement.php
index 3ad41f13e632..d47f47722ba1 100644
--- a/typo3/sysext/backend/Classes/Form/Element/InputLinkElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/InputLinkElement.php
@@ -36,6 +36,17 @@ use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;
  */
 class InputLinkElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field controls render the link icon
      *
@@ -93,10 +104,15 @@ class InputLinkElement extends AbstractFormElement
         $width = (int)$this->formMaxWidth($size);
         $nullControlNameEscaped = htmlspecialchars('control[active][' . $table . '][' . $row['uid'] . '][' . $fieldName . ']');
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if ($config['readOnly']) {
             // Early return for read only fields
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
@@ -186,10 +202,6 @@ class InputLinkElement extends AbstractFormElement
             $valuePickerHtml[] = '</select>';
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldWizardResult = $this->renderFieldWizard();
         $fieldWizardHtml = $fieldWizardResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
diff --git a/typo3/sysext/backend/Classes/Form/Element/InputTextElement.php b/typo3/sysext/backend/Classes/Form/Element/InputTextElement.php
index 80bcfbf6d26d..42baeda16058 100644
--- a/typo3/sysext/backend/Classes/Form/Element/InputTextElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/InputTextElement.php
@@ -27,6 +27,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class InputTextElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -72,6 +83,10 @@ class InputTextElement extends AbstractFormElement
         $width = (int)$this->formMaxWidth($size);
         $nullControlNameEscaped = htmlspecialchars('control[active][' . $table . '][' . $row['uid'] . '][' . $fieldName . ']');
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if ($config['readOnly']) {
             // Early return for read only fields
             if (in_array('password', $evalList, true)) {
@@ -79,6 +94,7 @@ class InputTextElement extends AbstractFormElement
             }
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
@@ -199,10 +215,6 @@ class InputTextElement extends AbstractFormElement
             $valueSliderHtml[] = '</div>';
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldControlResult = $this->renderFieldControl();
         $fieldControlHtml = $fieldControlResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
diff --git a/typo3/sysext/backend/Classes/Form/Element/NoneElement.php b/typo3/sysext/backend/Classes/Form/Element/NoneElement.php
index d9fec9ecc438..c77a3e8cbeee 100644
--- a/typo3/sysext/backend/Classes/Form/Element/NoneElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/NoneElement.php
@@ -21,12 +21,23 @@ use TYPO3\CMS\Core\Utility\MathUtility;
  */
 class NoneElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * This will render a non-editable display of the content of the field.
      *
-     * @return string The HTML code for the TCEform field
+     * @return array The HTML code for the TCEform field
      */
-    public function render()
+    public function render(): array
     {
         $resultArray = $this->initializeResultArray();
 
diff --git a/typo3/sysext/backend/Classes/Form/Element/RadioElement.php b/typo3/sysext/backend/Classes/Form/Element/RadioElement.php
index a56fefa143f9..1da7c555ac7c 100644
--- a/typo3/sysext/backend/Classes/Form/Element/RadioElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/RadioElement.php
@@ -19,6 +19,17 @@ namespace TYPO3\CMS\Backend\Form\Element;
  */
 class RadioElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -56,49 +67,47 @@ class RadioElement extends AbstractFormElement
             $disabled = ' disabled';
         }
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
+        $fieldWizardResult = $this->renderFieldWizard();
+        $fieldWizardHtml = $fieldWizardResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
+
         $html = [];
+        $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+        $html[] = $fieldInformationHtml;
+        $html[] =   '<div class="form-wizards-wrap">';
+        $html[] =       '<div class="form-wizards-element">';
+
         foreach ($this->data['parameterArray']['fieldConf']['config']['items'] as $itemNumber => $itemLabelAndValue) {
             $label = $itemLabelAndValue[0];
             $value = $itemLabelAndValue[1];
             $radioId = htmlspecialchars($this->data['parameterArray']['itemFormElID'] . '_' . $itemNumber);
             $radioChecked = (string)$value === (string)$this->data['parameterArray']['itemFormElValue'] ? ' checked="checked"' : '';
 
-            $fieldInformationResult = $this->renderFieldInformation();
-            $fieldInformationHtml = $fieldInformationResult['html'];
-            $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
-            $fieldWizardResult = $this->renderFieldWizard();
-            $fieldWizardHtml = $fieldWizardResult['html'];
-            $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
-
-            $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-            if (!$disabled) {
-                $html[] = $fieldInformationHtml;
-            }
-            $html[] =   '<div class="form-wizards-wrap">';
-            $html[] =       '<div class="form-wizards-element">';
-            $html[] =           '<div class="radio' . $disabled . '">';
-            $html[] =               '<label for="' . $radioId . '">';
-            $html[] =                   '<input type="radio"';
-            $html[] =                       ' name="' . htmlspecialchars($this->data['parameterArray']['itemFormElName']) . '"';
-            $html[] =                       ' id="' . $radioId . '"';
-            $html[] =                       ' value="' . htmlspecialchars($value) . '"';
-            $html[] =                       $radioChecked;
-            $html[] =                       $disabled;
-            $html[] =                       ' onclick="' . htmlspecialchars(implode('', $this->data['parameterArray']['fieldChangeFunc'])) . '"';
-            $html[] =                   '/>';
-            $html[] =                       htmlspecialchars($this->appendValueToLabelInDebugMode($label, $value));
-            $html[] =               '</label>';
-            $html[] =           '</div>';
-            $html[] =       '</div>';
-            if (!$disabled) {
-                $html[] =   '<div class="form-wizards-items-bottom">';
-                $html[] =       $fieldWizardHtml;
-                $html[] =   '</div>';
-            }
-            $html[] =   '</div>';
+            $html[] = '<div class="radio' . $disabled . '">';
+            $html[] =     '<label for="' . $radioId . '">';
+            $html[] =     '<input type="radio"';
+            $html[] =         ' name="' . htmlspecialchars($this->data['parameterArray']['itemFormElName']) . '"';
+            $html[] =         ' id="' . $radioId . '"';
+            $html[] =         ' value="' . htmlspecialchars($value) . '"';
+            $html[] =         $radioChecked;
+            $html[] =         $disabled;
+            $html[] =         ' onclick="' . htmlspecialchars(implode('', $this->data['parameterArray']['fieldChangeFunc'])) . '"';
+            $html[] =     '/>';
+            $html[] =         htmlspecialchars($this->appendValueToLabelInDebugMode($label, $value));
+            $html[] =     '</label>';
             $html[] = '</div>';
         }
+        if (!$disabled) {
+            $html[] =   '<div class="form-wizards-items-bottom">';
+            $html[] =       $fieldWizardHtml;
+            $html[] =   '</div>';
+        }
+        $html[] =   '</div>';
+        $html[] = '</div>';
 
         $resultArray['html'] = implode(LF, $html);
         return $resultArray;
diff --git a/typo3/sysext/backend/Classes/Form/Element/SelectCheckBoxElement.php b/typo3/sysext/backend/Classes/Form/Element/SelectCheckBoxElement.php
index 96586cec9cfe..63a39ffe9f82 100644
--- a/typo3/sysext/backend/Classes/Form/Element/SelectCheckBoxElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/SelectCheckBoxElement.php
@@ -27,6 +27,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class SelectCheckBoxElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -145,9 +156,7 @@ class SelectCheckBoxElement extends AbstractFormElement
             $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
 
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-            if (!$disabled) {
-                $html[] = $fieldInformationHtml;
-            }
+            $html[] = $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
 
diff --git a/typo3/sysext/backend/Classes/Form/Element/SelectMultipleSideBySideElement.php b/typo3/sysext/backend/Classes/Form/Element/SelectMultipleSideBySideElement.php
index 258ed516c9ab..ba9ee4ae22fc 100644
--- a/typo3/sysext/backend/Classes/Form/Element/SelectMultipleSideBySideElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/SelectMultipleSideBySideElement.php
@@ -28,6 +28,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class SelectMultipleSideBySideElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field controls for this element.
      *
@@ -325,6 +336,7 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
     protected function renderReadOnly()
     {
         $languageService = $this->getLanguageService();
+        $resultArray = $this->initializeResultArray();
 
         $parameterArray = $this->data['parameterArray'];
         $config = $parameterArray['fieldConf']['config'];
@@ -363,8 +375,13 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
             }
         }
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+        $html[] =   $fieldInformationHtml;
         $html[] =   '<div class="form-wizards-wrap">';
         $html[] =       '<div class="form-wizards-element">';
         $html[] =           '<label>';
@@ -389,7 +406,6 @@ class SelectMultipleSideBySideElement extends AbstractFormElement
         $html[] =   '</div>';
         $html[] = '</div>';
 
-        $resultArray = $this->initializeResultArray();
         $resultArray['html'] = implode(LF, $html);
         return $resultArray;
     }
diff --git a/typo3/sysext/backend/Classes/Form/Element/SelectSingleBoxElement.php b/typo3/sysext/backend/Classes/Form/Element/SelectSingleBoxElement.php
index ff20f709c0a3..eacd0a650dcb 100644
--- a/typo3/sysext/backend/Classes/Form/Element/SelectSingleBoxElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/SelectSingleBoxElement.php
@@ -25,6 +25,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class SelectSingleBoxElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field controls for this element.
      *
@@ -112,9 +123,7 @@ class SelectSingleBoxElement extends AbstractFormElement
 
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-        if (!$disabled) {
-            $html[] = $fieldInformationHtml;
-        }
+        $html[] = $fieldInformationHtml;
         $html[] =   '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
         $html[] =       '<div class="form-wizards-wrap form-wizards-aside">';
         $html[] =           '<div class="form-wizards-element">';
diff --git a/typo3/sysext/backend/Classes/Form/Element/SelectSingleElement.php b/typo3/sysext/backend/Classes/Form/Element/SelectSingleElement.php
index a305ca362787..265afe1491ba 100644
--- a/typo3/sysext/backend/Classes/Form/Element/SelectSingleElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/SelectSingleElement.php
@@ -27,6 +27,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class SelectSingleElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -200,9 +211,7 @@ class SelectSingleElement extends AbstractFormElement
 
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-        if (!$disabled) {
-            $html[] = $fieldInformationHtml;
-        }
+        $html[] = $fieldInformationHtml;
         $html[] =   '<div class="form-control-wrap">';
         $html[] =       '<div class="form-wizards-wrap">';
         $html[] =           '<div class="form-wizards-element">';
diff --git a/typo3/sysext/backend/Classes/Form/Element/SelectTreeElement.php b/typo3/sysext/backend/Classes/Form/Element/SelectTreeElement.php
index 4b1020cdfcd3..079b0db06c89 100644
--- a/typo3/sysext/backend/Classes/Form/Element/SelectTreeElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/SelectTreeElement.php
@@ -21,6 +21,17 @@ namespace TYPO3\CMS\Backend\Form\Element;
  */
 class SelectTreeElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * @var array Default wizards
      */
@@ -124,9 +135,7 @@ class SelectTreeElement extends AbstractFormElement
 
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
-        if ($readOnly === 'false') {
-            $html[] = $fieldInformationHtml;
-        }
+        $html[] = $fieldInformationHtml;
         $html[] =   '<div class="form-control-wrap">';
         $html[] =       '<div class="form-wizards-wrap">';
         $html[] =           '<div class="form-wizards-element">';
diff --git a/typo3/sysext/backend/Classes/Form/Element/TextElement.php b/typo3/sysext/backend/Classes/Form/Element/TextElement.php
index 786950d5749f..ccf588acf030 100644
--- a/typo3/sysext/backend/Classes/Form/Element/TextElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/TextElement.php
@@ -25,6 +25,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class TextElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -94,9 +105,14 @@ class TextElement extends AbstractFormElement
             }
         }
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if ($config['readOnly']) {
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
@@ -189,10 +205,6 @@ class TextElement extends AbstractFormElement
             $valuePickerHtml[] = '</select>';
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldControlResult = $this->renderFieldControl();
         $fieldControlHtml = $fieldControlResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
diff --git a/typo3/sysext/backend/Classes/Form/Element/TextTableElement.php b/typo3/sysext/backend/Classes/Form/Element/TextTableElement.php
index f534ec18e844..e49a3e2db911 100644
--- a/typo3/sysext/backend/Classes/Form/Element/TextTableElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/TextTableElement.php
@@ -24,6 +24,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class TextTableElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -99,9 +110,14 @@ class TextTableElement extends AbstractFormElement
             }
         }
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if ($config['readOnly']) {
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
@@ -168,10 +184,6 @@ class TextTableElement extends AbstractFormElement
             $attributes['placeholder'] = htmlspecialchars(trim($config['placeholder']));
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldControlResult = $this->renderFieldControl();
         $fieldControlHtml = $fieldControlResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
diff --git a/typo3/sysext/backend/Classes/Form/FieldInformation/SiteConfiguration.php b/typo3/sysext/backend/Classes/Form/FieldInformation/TcaDescription.php
similarity index 58%
rename from typo3/sysext/backend/Classes/Form/FieldInformation/SiteConfiguration.php
rename to typo3/sysext/backend/Classes/Form/FieldInformation/TcaDescription.php
index 95949a736d62..3c57f4438c28 100644
--- a/typo3/sysext/backend/Classes/Form/FieldInformation/SiteConfiguration.php
+++ b/typo3/sysext/backend/Classes/Form/FieldInformation/TcaDescription.php
@@ -20,21 +20,25 @@ use TYPO3\CMS\Backend\Form\AbstractNode;
 use TYPO3\CMS\Core\Localization\LanguageService;
 
 /**
- * Provides field information texts for form engine fields concerning site configuration module
+ * Render localized ['columns']['theField']['description'] text as default
+ * field information node. This is typically displayed in elements below the
+ * element label and the field content.
  */
-class SiteConfiguration extends AbstractNode
+class TcaDescription extends AbstractNode
 {
     /**
      * Handler for single nodes
      *
      * @return array As defined in initializeResultArray() of AbstractNode
      */
-    public function render()
+    public function render(): array
     {
         $resultArray = $this->initializeResultArray();
-        $fieldInformationText = $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:' . $this->data['tableName'] . '.' . $this->data['fieldName']);
-        if ($fieldInformationText !== $this->data['fieldName']) {
-            $resultArray['html'] = $fieldInformationText;
+        if (!empty($this->data['parameterArray']['fieldConf']['description'])) {
+            $fieldInformationText = $this->getLanguageService()->sL($this->data['parameterArray']['fieldConf']['description']);
+            if (trim($fieldInformationText) !== '') {
+                $resultArray['html'] = htmlspecialchars($fieldInformationText);
+            }
         }
         return $resultArray;
     }
@@ -44,7 +48,7 @@ class SiteConfiguration extends AbstractNode
      *
      * @return LanguageService
      */
-    protected function getLanguageService()
+    protected function getLanguageService(): LanguageService
     {
         return $GLOBALS['LANG'];
     }
diff --git a/typo3/sysext/backend/Classes/Form/NodeFactory.php b/typo3/sysext/backend/Classes/Form/NodeFactory.php
index 46a175954f43..7b867fd43bfb 100644
--- a/typo3/sysext/backend/Classes/Form/NodeFactory.php
+++ b/typo3/sysext/backend/Classes/Form/NodeFactory.php
@@ -98,6 +98,9 @@ class NodeFactory
         'fieldInformation' => NodeExpansion\FieldInformation::class,
         'fieldWizard' => NodeExpansion\FieldWizard::class,
 
+        // Element information
+        'tcaDescription' => FieldInformation\TcaDescription::class,
+
         // Element wizards
         'defaultLanguageDifferences' => FieldWizard\DefaultLanguageDifferences::class,
         'fileThumbnails' => FieldWizard\FileThumbnails::class,
diff --git a/typo3/sysext/backend/Configuration/SiteConfiguration/site.php b/typo3/sysext/backend/Configuration/SiteConfiguration/site.php
index ab4ae8562754..58e3c6b5b178 100644
--- a/typo3/sysext/backend/Configuration/SiteConfiguration/site.php
+++ b/typo3/sysext/backend/Configuration/SiteConfiguration/site.php
@@ -11,6 +11,7 @@ return [
     'columns' => [
         'identifier' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site.identifier',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site.identifier',
             'config' => [
                 'type' => 'input',
                 'size' => 35,
@@ -18,11 +19,6 @@ return [
                 // identifier is used as directory name - allow a-z,0-9,_,- as chars only.
                 // unique is additionally checked server side
                 'eval' => 'required,lower,alphanum_x',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'rootPageId' => [
@@ -33,23 +29,14 @@ return [
                 'renderType' => 'selectSingle',
                 'foreign_table' => 'pages',
                 'foreign_table_where' => ' AND (is_siteroot=1 OR (pid=0 AND doktype IN (1,6,7))) AND l10n_parent = 0 ORDER BY pid, sorting',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'base' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site.base',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site.base',
             'config' => [
                 'type' => 'input',
                 'eval' => 'required',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'languages' => [
diff --git a/typo3/sysext/backend/Configuration/SiteConfiguration/site_errorhandling.php b/typo3/sysext/backend/Configuration/SiteConfiguration/site_errorhandling.php
index 71e9ed5120ec..1b6ebf0b0609 100644
--- a/typo3/sysext/backend/Configuration/SiteConfiguration/site_errorhandling.php
+++ b/typo3/sysext/backend/Configuration/SiteConfiguration/site_errorhandling.php
@@ -16,6 +16,7 @@ return [
     'columns' => [
         'errorCode' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_errorhandling.errorCode',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site_errorhandling.errorCode',
             'config' => [
                 'type' => 'input',
                 'eval' => 'required, trim, int',
@@ -35,11 +36,6 @@ return [
                         ['LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_errorhandling.errorCode.0', '0'],
                     ],
                 ],
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'errorHandler' => [
@@ -53,56 +49,32 @@ return [
                     ['Show Content from Page', 'Page'],
                     ['PHP Class (must implement the PageErrorHandlerInterface)', 'PHP'],
                 ],
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'errorFluidTemplate' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_errorhandling.errorFluidTemplate',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site_errorhandling.errorFluidTemplate',
             'config' => [
                 'type' => 'input',
                 'eval' => 'required',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'errorFluidTemplatesRootPath' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_errorhandling.errorFluidTemplatesRootPath',
             'config' => [
                 'type' => 'input',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'errorFluidLayoutsRootPath' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_errorhandling.errorFluidLayoutsRootPath',
             'config' => [
                 'type' => 'input',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'errorFluidPartialsRootPath' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_errorhandling.errorFluidPartialsRootPath',
             'config' => [
                 'type' => 'input',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'errorContentSource' => [
@@ -111,11 +83,6 @@ return [
                 'type' => 'input',
                 'renderType' => 'inputLink',
                 'eval' => 'required',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
                 'fieldControl' => [
                     'linkPopup' => [
                         'options' => [
@@ -127,14 +94,10 @@ return [
         ],
         'errorPhpClassFQCN' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_errorhandling.errorPhpClassFQCN',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site_errorhandling.errorPhpClassFQCN',
             'config' => [
                 'type' => 'input',
                 'eval' => 'required',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
     ],
diff --git a/typo3/sysext/backend/Configuration/SiteConfiguration/site_language.php b/typo3/sysext/backend/Configuration/SiteConfiguration/site_language.php
index 28caf8fda939..f3ff5b42803d 100644
--- a/typo3/sysext/backend/Configuration/SiteConfiguration/site_language.php
+++ b/typo3/sysext/backend/Configuration/SiteConfiguration/site_language.php
@@ -21,11 +21,6 @@ return [
                 'size' => 1,
                 'min' => 1,
                 'max' => 1,
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'title' => [
@@ -35,11 +30,6 @@ return [
                 'size' => 10,
                 'eval' => 'required',
                 'placeholder' => 'English',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'navigationTitle' => [
@@ -48,37 +38,24 @@ return [
                 'type' => 'input',
                 'size' => 10,
                 'placeholder' => 'English',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'base' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_language.base',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site_language.base',
             'config' => [
                 'type' => 'input',
                 'eval' => 'required',
                 'default' => '/',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'locale' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_language.locale',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site_language.locale',
             'config' => [
                 'type' => 'input',
                 'eval' => 'required',
                 'placeholder' => 'en_US.UTF-8',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'iso-639-1' => [
@@ -88,11 +65,6 @@ return [
                 'renderType' => 'selectSingle',
                 // Fed by data provider
                 'items' => [],
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'hreflang' => [
@@ -100,11 +72,6 @@ return [
             'config' => [
                 'type' => 'input',
                 'placeholder' => 'en-US',
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'direction' => [
@@ -117,25 +84,16 @@ return [
                     ['Left to Right', 'ltr', ''],
                     ['Right to Left', 'rtl', ''],
                 ],
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'typo3Language' => [
             'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang_siteconfiguration_tca.xlf:site_language.typo3Language',
+            'description' => 'LLL:EXT:backend/Resources/Private/Language/siteconfiguration_fieldinformation.xlf:site_language.typo3Language',
             'config' => [
                 'type' => 'select',
                 'renderType' => 'selectSingle',
                 // Fed by data provider
                 'items' => [],
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
                 'default' => 'default'
             ],
         ],
@@ -404,11 +362,6 @@ return [
                         'disabled' => false,
                     ],
                 ],
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'fallbackType' => [
@@ -422,11 +375,6 @@ return [
                     ['No fallback (strict)', 'strict'],
                     ['Fallback to other language', 'fallback'],
                 ],
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
         'fallbacks' => [
@@ -441,11 +389,6 @@ return [
                 'foreign_table' => 'sys_language',
                 'size' => 5,
                 'min' => 0,
-                'fieldInformation' => [
-                    'SiteConfigurationModuleFieldInformation' => [
-                        'renderType' => 'SiteConfigurationModuleFieldInformation',
-                    ],
-                ],
             ],
         ],
     ],
diff --git a/typo3/sysext/backend/ext_localconf.php b/typo3/sysext/backend/ext_localconf.php
index c06b0372611f..073da8db5ace 100644
--- a/typo3/sysext/backend/ext_localconf.php
+++ b/typo3/sysext/backend/ext_localconf.php
@@ -43,10 +43,3 @@ $GLOBALS['TYPO3_CONF_VARS']['SYS']['livesearch']['page'] = 'pages';
 
 // Register BackendLayoutDataProvider for PageTs
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider']['pagets'] = \TYPO3\CMS\Backend\Provider\PageTsBackendLayoutDataProvider::class;
-
-// Register fieldInformation Provider for site configuration module
-$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1522919823] = [
-    'nodeName' => 'SiteConfigurationModuleFieldInformation',
-    'priority' => '70',
-    'class' => \TYPO3\CMS\Backend\Form\FieldInformation\SiteConfiguration::class
-];
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-85410-AllowTCADescriptionProperty.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-85410-AllowTCADescriptionProperty.rst
new file mode 100644
index 000000000000..21dca74f7c3c
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-85410-AllowTCADescriptionProperty.rst
@@ -0,0 +1,40 @@
+.. include:: ../../Includes.txt
+
+================================================
+Feature: #85410 - Allow TCA description property
+================================================
+
+See :issue:`85410`
+
+Description
+===========
+
+The new `TCA` property `description` on column field level has been introduced.
+The value data type is a localized string, similar and on the same level as `label`.
+
+The property can be used to display an additional help text between the field label and
+the user input when editing records. As an example, the core uses the description property
+in the site configuration module when editing a site on some properties like `identifier`.
+
+The property is available on all common `TCA` types like `input` and `select` and so on.
+
+Example::
+
+    'columns' => [
+        'myField' => [
+            'label' => 'My label',
+            'description' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:field.description',
+            'config' => [
+                'type' => 'input',
+            ],
+        ],
+    ],
+
+
+Impact
+======
+
+The change is fully backwards compatible and can be used by integrators or administrators
+to hint editors for expected field input.
+
+.. index:: Backend, FlexForm, TCA
diff --git a/typo3/sysext/rsaauth/Classes/Form/Element/RsaInputElement.php b/typo3/sysext/rsaauth/Classes/Form/Element/RsaInputElement.php
index 6a5e858c30ab..18b380cb2068 100644
--- a/typo3/sysext/rsaauth/Classes/Form/Element/RsaInputElement.php
+++ b/typo3/sysext/rsaauth/Classes/Form/Element/RsaInputElement.php
@@ -24,6 +24,17 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  */
 class RsaInputElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
@@ -60,6 +71,10 @@ class RsaInputElement extends AbstractFormElement
         $width = (int)$this->formMaxWidth($size);
         $isPasswordField = in_array('password', $evalList, true);
 
+        $fieldInformationResult = $this->renderFieldInformation();
+        $fieldInformationHtml = $fieldInformationResult['html'];
+        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
+
         if ($config['readOnly']) {
             // Early return for read only fields
             if ($isPasswordField) {
@@ -67,6 +82,7 @@ class RsaInputElement extends AbstractFormElement
             }
             $html = [];
             $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
+            $html[] =   $fieldInformationHtml;
             $html[] =   '<div class="form-wizards-wrap">';
             $html[] =       '<div class="form-wizards-element">';
             $html[] =           '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
@@ -137,10 +153,6 @@ class RsaInputElement extends AbstractFormElement
             $attributes['autocomplete'] = 'new-' . $fieldName;
         }
 
-        $fieldInformationResult = $this->renderFieldInformation();
-        $fieldInformationHtml = $fieldInformationResult['html'];
-        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
-
         $fieldControlResult = $this->renderFieldControl();
         $fieldControlHtml = $fieldControlResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
diff --git a/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php b/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php
index c60afd49347b..a12b8bd0cb50 100644
--- a/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php
+++ b/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php
@@ -27,6 +27,17 @@ use TYPO3\CMS\Core\Utility\PathUtility;
  */
 class RichTextElement extends AbstractFormElement
 {
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
diff --git a/typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php b/typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php
index 59aee66ecd1a..600f2991201d 100644
--- a/typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php
+++ b/typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php
@@ -48,6 +48,17 @@ class T3editorElement extends AbstractFormElement
      */
     protected $extPath = '';
 
+    /**
+     * Default field information enabled for this element.
+     *
+     * @var array
+     */
+    protected $defaultFieldInformation = [
+        'tcaDescription' => [
+            'renderType' => 'tcaDescription',
+        ],
+    ];
+
     /**
      * Default field wizards enabled for this element.
      *
-- 
GitLab