diff --git a/extension/Classes/Core/AbstractBuildForm.php b/extension/Classes/Core/AbstractBuildForm.php
index ba1b8b9f8c41a95c0cd1f04fbb7ee433ce198b7a..c936c6096db45a3a88d758febc0e3c7a4f6f1dce 100644
--- a/extension/Classes/Core/AbstractBuildForm.php
+++ b/extension/Classes/Core/AbstractBuildForm.php
@@ -3436,9 +3436,29 @@ abstract class AbstractBuildForm {
         } else {
             $completeUrl = '?action=imageUpload';
         }
+
+        // Prepare maxLength and characterCount for tinyMce
+        $maxLength = $formElement[FE_MAX_LENGTH];
+        $elementCharacterCount = '';
+        if (isset($formElement[FE_CHARACTER_COUNT_WRAP])) {
+            $attribute .= Support::doAttribute('data-character-count-id', $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_CHARACTER_COUNT);
+            $attributeCC = Support::doAttribute('id', $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_CHARACTER_COUNT);
+            $classCC = ($formElement[FE_CHARACTER_COUNT_WRAP] == '') ? Support::doAttribute('class', 'qfq-cc-style') : '';
+            $elementCharacterCount = "<span $attributeCC $classCC></span>";
+
+            if ($formElement[FE_CHARACTER_COUNT_WRAP] != '') {
+                $arr = explode('|', $formElement[FE_CHARACTER_COUNT_WRAP], 2);
+                $arr[] = '';
+                $arr[] = ''; //skip check that at least 2 elements exist
+                $elementCharacterCount = $arr[0] . $elementCharacterCount . $arr[1];
+            }
+        }
+
 //TODO: static setup for TinyMCE ImagePlugin - needs to be activated / dynamically set by QFQ parameter.
         $preSettings = [
 #            "plugins" => "image",
+            "plugins" => "charmap",
+            "maxLength" => $maxLength,
             "file_picker_types" => "file image media",
             "image_advtab" => true,
             "automatic_uploads" => true,
@@ -3460,7 +3480,7 @@ abstract class AbstractBuildForm {
         $html = Support::wrapTag("<textarea $attribute>", htmlentities($value), false);
         $formElement = HelperFormElement::prepareExtraButton($formElement, false);
 
-        return $html . HelperFormElement::getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
+        return $html . HelperFormElement::getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . $elementCharacterCount . $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
     }
 
     /**
diff --git a/javascript/src/Helper/tinyMCE.js b/javascript/src/Helper/tinyMCE.js
index 892ef1b4be8b957a1f30162f1f6d122a19467932..095bbbe5c4f9e6e69831e3fa6a23f33bec2258d2 100644
--- a/javascript/src/Helper/tinyMCE.js
+++ b/javascript/src/Helper/tinyMCE.js
@@ -59,6 +59,36 @@ QfqNS.Helper = QfqNS.Helper || {};
                 config.setup = function (editor) {
                     myEditor = editor;
                     var element = document.getElementById(QfqNS.escapeJqueryIdSelector(tinyMCEId));
+
+                    var counterFlag = false;
+                    if ($this.data('character-count-id') !== undefined) {
+                        counterFlag = true;
+                    }
+                    var maxLength = config.maxLength; // set the maximum length here
+                    var maxLengthDisplay = maxLength;
+                    if (maxLength === '' || maxLength === 0) {
+                        maxLength = false;
+                        maxLengthDisplay = "∞";
+                    }
+
+                    var pattern = /[^\r\n\t\v\f ]/g;
+
+                    editor.on('init', function() {
+                        if (maxLength) {
+                            editor.dom.setAttrib(editor.getBody(), 'maxlength', maxLength);
+                        }
+
+                        // initialize counter after first load
+                        if (counterFlag) {
+                            var content = editor.getContent({format: 'text'});
+                            var charCount = (content.match(pattern) || []).length;
+                            var characterCountTarget = "#" + $this.data('character-count-id');
+
+                            $this.data('character-count-display', $(characterCountTarget));
+                            $this.data('character-count-display').text(charCount + "/" + maxLengthDisplay);
+                        }
+                    });
+
                     editor.on('Change drop', function (e) {
                         // Ensure the associated form is notified of changes in editor.
                         QfqNS.Log.debug('Editor was changed');
@@ -70,11 +100,36 @@ QfqNS.Helper = QfqNS.Helper || {};
                         $parentForm.trigger("change");
                     });
 
+                    var inputFlag = false;
+                    // Needed for accurate character count. Update counter after input or keyup.
+                    editor.on('input keyup', function() {
+                        if (counterFlag) {
+                            var content = editor.getContent({format: 'text'});
+                            var charCount = (content.match(pattern) || []).length;
+                            $this.data('character-count-display').text(charCount + "/" + maxLengthDisplay);
+                        }
+                        inputFlag = true;
+                    });
+
+                    // Preventing input of more than maxLength
+                    editor.on('keydown', function(e) {
+                        if (maxLength) {
+                            var content = editor.getContent({format: 'text'}); // get content without HTML tags
+                            var charCount = (content.match(pattern) || []).length;
+                            if (charCount >= maxLength && e.keyCode !== 8) { // prevent input when maximum length is reached
+                                e.preventDefault();
+                                e.stopPropagation();
+                            }
+                        }
+                    });
+
                     // Trigger enabled dynamic update for tinyMce after focus out
                     // To get content via dynamic update: It needs to be written in textarea value
                     editor.on('blur', function () {
                         element.value = tinymce.get(QfqNS.escapeJqueryIdSelector(tinyMCEId)).getContent();
-                        $(config.selector).trigger('change');
+                        if (inputFlag) {
+                            $(config.selector).trigger('change');
+                        }
                     });
 
                     /* Remove ReadOnly Again - we have to implement tinymce differently