TYPO3 RTE for Input Fields
Published: , Updated:
Tested with TYPO3: 10 LTS
Topics: typo3
Introduction ¶
Sometimes a headline needs to use line breaks or formatting like italic words. Some integrators define placeholders like [BR] which get substituted. We use TYPO3 native RTE functionality with stripped down configuration. This small post describes how we set it up. The goal is to have a small field and features like limited number of characters and reduced formatting possibilities.

The Problem ¶
Sometimes editors need to insert line breaks <br>
or special characters like ⓒ and a reduced set of formatting like superscript or italic within headlines or other input fields of TYPO3. This might be necessary because a headline references a product or company.
But that's not possible with TYPO3 native input fields. Editors might not be aware of system features to insert special characters and even then they won't be able to insert line breaks or formatting within those fields.
Existing Approaches ¶
Some approach we've seen so far:
Provide a documentation with special characters for copy and paste.
We don't like this approach as editors need to switch between TYPO3 and another system holding the documentation for copy and paste which itself is not a nice workflow.
Provide special sequences like [BR]
(good old BB-Code style 😉). Those become replaced via TypoScript.
We don't like this as well as you need to document those sequences. And they are more or less HTML in the end, just different braces. One big goal of most CMS is to remove the need for editors to write HTML.
Our Approach ¶
We thought we could use a very reduced RTE configuration for those fields. The goal would be to have a small input field instead of a huge text area. Furthermore, only the necessary formatting should be provided, resulting in a very small toolbar. That would allow an already known way to format text and insert special characters. Editors won't need to learn something new.
TYPO3 offers the option rows
for <textarea>
inputs to define how large an input should be. Furthermore, TYPO3 provides a max
option for input
to limit the number of characters. That's important to not lose input after persisting to database. Both should be respected as well. Allowing integrators and developers to use existing approaches and documented options.
TYPO3 by default processes the input when storing and retrieving from database. It for example will wrap lines with <p>
tags. We don't want that, as it should be handled like a normal input field.
We use a dedicated RTE configuration and a small EventListener. The configuration will provide the wordcount plugin, adjust the processing of the input and define which formatting options should be available. The Listener should connect the TCA configuration for rows
and max
to the RTE, by adjusting the configuration.
The Configuration ¶
The configuration of figure i52 looks like this:
imports:
- {resource: "EXT:rte_ckeditor/Configuration/RTE/Editor/Base.yaml"}
- {resource: "EXT:e2_core/Configuration/RTE/Editor/SpecialChars.yaml"}
editor:
config:
allowedContent: true
enableContextMenu: false
forcePasteAsPlainText: true
clipboard_defaultContentType: 'text'
toolbar:
- ['Subscript', 'Superscript', '-', 'SpecialChar']
wordcount:
showRemaining: true
showParagraphs: false
showWordCount: false
showCharCount: true
# Filled by Event based on TCA configuration
# maxCharCount: 255
autoParagraph: false
enterMode: 2 # <br> instead of <p>
extraPlugins:
- wordcount
- specialchar
removePlugins:
- resize
- autogrow
processing:
overruleMode: nothing
allowTags:
- sub
- sup
- br
This removes some unwanted features like autogrow, manual resize and context menu.
It also only allows the expected formatting and tags. Furthermore, it configures that line breaks instead of paragraphs should be inserted.
It also imports a global configuration defining the actual special characters needed by editors in this system. TYPO3 v12 will update to CKEditor 5 where special characters UI becomes event better, see: https://ckeditor.com/docs/ckeditor5/latest/features/special-characters.html.
Wordcount is also pre-configured. It will behave like max of input fields and prevent further characters exceeding the maximum count. The count itself is not defined but will be inserted via EventListener based on TCA configuration. One could pre-configure a value within the configuration which can be overwritten via TCA.
The overruleMode: nothing
blocks TYPO3 default processing of HTML while inserting and reading from database. This blocks wrapping within <p>
tags.
The Event Listener ¶
The Listener looks like this:
declare(strict_types=1);
namespace E2\E2Core\EventListener;
use TYPO3\CMS\RteCKEditor\Form\Element\Event\AfterPrepareConfigurationForEditorEvent;
/**
* Transports some of the TCA features into RTE.
*
* RTE can limit input based on a count, just like TCA 'max' property.
*/
class TcaToRteConfiguration
{
public function __invoke(AfterPrepareConfigurationForEditorEvent $event): void
{
$rteConfiguration = $event->getConfiguration();
$fieldConfiguration = $event->getData()['parameterArray']['fieldConf']['config'] ?? [];
$rteConfiguration = $this->setRows($rteConfiguration, $fieldConfiguration);
$rteConfiguration = $this->setMax($rteConfiguration, $fieldConfiguration);
$event->setConfiguration($rteConfiguration);
}
private function setRows(array $rteConfiguration, array $fieldConfiguration): array
{
$rows = $fieldConfiguration['rows'] ?? 0;
if ($rows > 0) {
$rteConfiguration['height'] = ($rows * 6) . 'rem';
}
return $rteConfiguration;
}
private function setMax(array $rteConfiguration, array $fieldConfiguration): array
{
$max = $fieldConfiguration['max'] ?? 0;
if ($max > 0) {
$rteConfiguration['wordcount']['maxCharCount'] = (int) $max;
}
return $rteConfiguration;
}
}
And is registered like this (within Services.yaml
of the extension):
services:
_defaults:
autowire: true
autoconfigure: true
public: false
E2\E2Core\:
resource: '../Classes/*'
E2\E2Core\EventListener\TcaToRteConfiguration:
tags:
- name: 'event.listener'
event: 'TYPO3\CMS\RteCKEditor\Form\Element\Event\AfterPrepareConfigurationForEditorEvent'
Combining the pieces ¶
We need to properly configure our TCA column to use the dedicated configuration. The column looks like this:
'tx_e2core_link_label_label' => [
'label' => $languagePath . 'tx_e2core_link_label_label',
'config' => [
'type' => 'text',
'eval' => 'required,trim',
'max' => 255,
'rows' => 1,
'enableRichtext' => true,
'richtextConfiguration' => 'minimal-input-field',
],
],
This converts our input to a text field. It is still required and gets trimmed. The max
and rows
are respected via above EventListener. The last two turn the field into an RTE with our dedicated configuration.
The RTE configuration itself is registered within ext_localconf.php
:
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule(
$GLOBALS['TYPO3_CONF_VARS'],
[
'RTE' => [
'Presets' => [
'default' => 'EXT:e2_core/Configuration/RTE/Editor/Custom.yaml',
'minimal-input-field' => 'EXT:e2_core/Configuration/RTE/Editor/MinimalInputField.yaml',
],
],
]
);
We prefer the merge way as we don't have different ways to configure the $GLOBALS['TYPO3_CONF_VARS']
. It is always this way within AdditionalConfiguration.php
, LocalConfiguration.php
and ext_localconf.php
. That allows to copy and paste without adjusting the code.
Our Takeaway ¶
We first thought there must be an extension or we should build an extension. That one should provide a new renderType
for TCA input
columns. We knew many others have the same issue and one of them should have already done that.
But we didn't find an extension and thought there should be an easier way and came up with our solution. That one is so flexible and easy to integrate that it doesn't make sense to provide an extension but a blog post. Every installation and even some fields have very special needs which now can be covered with different configurations.
We love flexible and simple solutions as they are the best solutions most of the time. To us, it is important to overthink solutions and approaches from the past. It is also critical to not get driven by technology hype or by the feeling to release another extension. Find a proper solution for the actual problem, ignoring other influences from the outside. It is still possible to share those solutions. Either as blog post, video or a small gist or some other way.
Acknowledgements ¶
Thanks to my co-worker Justus Moroni who once more helped to provide a good solution for a problem.
Thanks to our customer reuter.de who allows us to re-think existing solutions in order to improve editor UX.
Thanks to Codappix GmbH for allowing me to share our solutions on my own blog during working hours.
Further reading ¶
- https://docs.typo3.org/c/typo3/cms-rte-ckeditor/main/en-us/Configuration/ConfigureTypo3.html - General CKEditor documentation for TYPO3
- https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html - All configuration options of CKEditor
- https://github.com/w8tcha/CKEditor-WordCount-Plugin - Configuration of WordCount plugin for CKEditor
- https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Events/EventDispatcher/Index.html - Event Dispatcher / PSR-14 Events documentation for TYPO3