Input 

type='input' generates a html <input> field with the type attribute set to text . It is possible to apply additional features such as the valuePicker.

The according database field is generated automatically. For short input fields allowing less than 255 chars VARCHAR() is used, TEXT for larger input fields.

Extension authors who need or want to override default TCA schema details for whatever reason, can do so by defining something specific in ext_tables.sql.

Changed in version 13.2

Tables with TCA columns set to type="input" do not need an ext_tables.sql entry anymore. The Core now creates this column automatically.

Examples 

Simple input field 

The title of a conference

The title of a conference

EXT:my_extension/Configuration/TCA/tx_myextension_conference.php
<?php

return [
  'ctrl' => [
    'title' => 'my_extension.db:conference',
    'label' => 'title',
    'descriptionColumn' => 'internal_notes',
    'default_sortby' => 'conference_date DESC',
    'tstamp' => 'tstamp',
    'crdate' => 'crdate',
    'delete' => 'deleted',
    'editlock' => 'editlock',
    'enablecolumns' => [
      'disabled' => 'hidden',
      'starttime' => 'starttime',
      'endtime' => 'endtime',
      'fe_group' => 'fe_group',
    ],
    'languageField' => 'sys_language_uid',
    'transOrigPointerField' => 'l10n_parent',
    'transOrigDiffSourceField' => 'l10n_diffsource',
    'translationSource' => 'l10n_source',
    'versioningWS' => true,
    'origUid' => 't3_origuid',
    'iconfile' => 'EXT:my_extension/Resources/Public/Icons/Conference.svg',
    'security' => [
      'ignorePageTypeRestriction' => true,
    ],
  ],
  'columns' => [
    'title' => [
      'label' => 'my_extension.db:conference.title',
      'config' => [
        'type' => 'input',
        'required' => true,
        'max' => 255,
        'eval' => 'trim',
      ],
    ],
    'conference_date' => [
      'label' => 'my_extension.db:conference.conference_date',
      'config' => [
        'type' => 'datetime',
        'format' => 'date',
        'required' => true,
      ],
    ],
    'internal_notes' => [
      'label' => 'my_extension.db:conference.internal_notes',
      'config' => [
        'type' => 'text',
        'rows' => 3,
      ],
    ],
  ],
  // The fields of the other tabs are added in Configuration/TCA/Overrides/
  'types' => [
    '0' => [
      'showitem' => '
        title, conference_date,
        --div--;my_extension.db:tab.program,
        --div--;my_extension.db:tab.details,
        --div--;core.form.tabs:categories,
        --div--;core.form.tabs:access,
          hidden, --palette--;;access, fe_group, editlock,
        --div--;core.form.tabs:language,
          --palette--;;language,
        --div--;my_extension.db:tab.comments,
        --div--;core.form.tabs:notes,
          internal_notes,
      ',
    ],
  ],
  'palettes' => [
    'access' => [
      'label' => 'core.form.palettes:access',
      'showitem' => 'starttime, endtime',
    ],
    'language' => [
      'showitem' => 'sys_language_uid, l10n_parent',
    ],
  ],
];
Copied!

Input with placeholder and null handling 

The short title of a conference shows the title as placeholder. If the editor sets no short title, the field stays NULL :

The short title of a conference, with the title as placeholder

The short title of a conference, with the title as placeholder

EXT:my_extension/Configuration/TCA/Overrides/106-tx_myextension_conference-short_title.php
<?php

use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

defined('TYPO3') or die();

ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
  'short_title' => [
    'label' => 'my_extension.db:conference.short_title',
    'config' => [
      'type' => 'input',
      'max' => 50,
      'placeholder' => '__row|title',
      'nullable' => true,
      'default' => null,
      'mode' => 'useOrOverridePlaceholder',
      'behaviour' => [
        'allowLanguageSynchronization' => true,
      ],
    ],
  ],
]);
ExtensionManagementUtility::addToAllTCAtypes(
  'tx_myextension_conference',
  'short_title',
  '',
  'after:title',
);
Copied!

Value picker 

The room of a talk offers the rooms of the venue to choose from:

The room of a talk with its value picker opened

The room of a talk with its value picker opened

EXT:my_extension/Configuration/TCA/tx_myextension_talk.php
<?php

return [
  'ctrl' => [
    'title' => 'my_extension.db:talk',
    'label' => 'title',
    'type' => 'talk_type',
    'typeicon_column' => 'talk_type',
    'typeicon_classes' => [
      'default' => 'my-extension-talk',
      'workshop' => 'my-extension-talk-workshop',
      'keynote' => 'my-extension-talk-keynote',
    ],
    'sortby' => 'sorting',
    'useColumnsForDefaultValues' => 'talk_type,room',
    'hideTable' => true,
    'tstamp' => 'tstamp',
    'crdate' => 'crdate',
    'delete' => 'deleted',
    'enablecolumns' => [
      'disabled' => 'hidden',
    ],
    'languageField' => 'sys_language_uid',
    'transOrigPointerField' => 'l10n_parent',
    'versioningWS' => true,
  ],
  'columns' => [
    'talk_type' => [
      'label' => 'my_extension.db:talk.talk_type',
      'config' => [
        'type' => 'select',
        'renderType' => 'selectSingle',
        'items' => [
          [
            'label' => 'my_extension.db:talk.talk_type.talk',
            'value' => 'talk',
          ],
          [
            'label' => 'my_extension.db:talk.talk_type.workshop',
            'value' => 'workshop',
          ],
          [
            'label' => 'my_extension.db:talk.talk_type.keynote',
            'value' => 'keynote',
          ],
        ],
        'default' => 'talk',
      ],
    ],
    'title' => [
      'label' => 'my_extension.db:talk.title',
      'config' => [
        'type' => 'input',
        'required' => true,
      ],
    ],
    'room' => [
      'label' => 'my_extension.db:talk.room',
      'config' => [
        'type' => 'input',
        'valuePicker' => [
          'items' => [
            ['label' => 'Main hall', 'value' => 'Main hall'],
            ['label' => 'Room A', 'value' => 'Room A'],
            ['label' => 'Room B', 'value' => 'Room B'],
          ],
        ],
      ],
    ],
  ],
  'types' => [
    'talk' => [
      'showitem' => '
        talk_type, title, room,
        --div--;core.form.tabs:access, hidden,
      ',
    ],
    'workshop' => [
      'showitem' => '
        talk_type, title, room,
        --div--;core.form.tabs:access, hidden,
      ',
    ],
    'keynote' => [
      'showitem' => '
        talk_type, title, room,
        --div--;core.form.tabs:access, hidden,
      ',
    ],
  ],
];
Copied!

Properties of the TCA column type input 

Name Type Scope
boolean Proc.
boolean Display
string Display / Proc.
string (list of keywords) Display / Proc.
array
array
array
string Display / Proc.
integer Display
integer Display
string (keywords) Display
boolean Proc.
string Display
boolean Display
boolean Display / Proc.
boolean Display
integer Display
string Proc.
array Display
behaviour
allowLanguageSynchronization
Type
boolean
Default
false
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['behaviour']['allowLanguageSynchronization']
Scope
Proc.

Allows an editor to select in a localized record whether the value is copied over from default or source language record, or if the field has an own value in the localization. If set to true and if the table supports localization and if a localized record is edited, this setting enables FieldWizard LocalizationStateSelector: Two or three radio buttons shown below the field input. The state of this is stored in a json encoded array in the database table called l10n_state. It tells the DataHandler which fields of the localization records should be kept in sync if the underlying default or source record changes.

EXT:my_extension/Configuration/TCA/Overrides/106-tx_myextension_conference-short_title.php
<?php

use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

defined('TYPO3') or die();

ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
  'short_title' => [
    'label' => 'my_extension.db:conference.short_title',
    'config' => [
      'type' => 'input',
      'max' => 50,
      'placeholder' => '__row|title',
      'nullable' => true,
      'default' => null,
      'mode' => 'useOrOverridePlaceholder',
      'behaviour' => [
        'allowLanguageSynchronization' => true,
      ],
    ],
  ],
]);
ExtensionManagementUtility::addToAllTCAtypes(
  'tx_myextension_conference',
  'short_title',
  '',
  'after:title',
);
Copied!
autocomplete
Type
boolean
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['autocomplete']
Scope
Display

Controls the autocomplete attribute of a given input field. If set to true (default false), adds attribute autocomplete="on" to the input field allowing browser auto filling the field:

'autocomplete' => true,
Copied!
default
Type
string
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['default']
Scope
Display / Proc.

Default value set if a new record is created. If empty, no input gets selected.

eval
Type
string (list of keywords)
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['eval']
Scope
Display / Proc.

Configuration of field evaluation. See also input fields with eval.

Some of these evaluation keywords will trigger a JavaScript pre- evaluation in the form. Other evaluations will be performed in the backend. The evaluation functions will be executed in the list-order. Keywords:

alpha
Allows only a-zA-Z characters.
alphanum
Same as "alpha" but allows also "0-9"
alphanum_x
Same as "alphanum" but allows also "_" and "-" chars.
domainname
Allows a domain name such as example.org and automatically transforms the value to punicode if needed.
is_in
Will filter out any character in the input string which is not found in the string entered in the property is_in.
lower
Converts the string to lowercase (only A-Z plus a selected set of Western European special chars).
md5
Will convert the input value to its md5-hash using a JavaScript function.
nospace
Removes all occurrences of space characters ( chr(32) )
num
Allows only 0-9 characters in the field.
trim
The value in the field will have white spaces around it trimmed away.
unique

Requires the field to be unique for the whole table. Evaluated on the server only.

uniqueInPid
Requires the field to be unique for the current PID among other records on the same page. Evaluated on the server only.
upper
Converts to uppercase (only A-Z plus a selected set of Western European special chars).
year

Changed in version 14.0

The previous implementation simply cast the year to an integer. Consider using more appropriate field types like 'number' or 'datetime' for better data handling and validation.

Evaluates the input to any number. This is actually a historically wrongly named evaluation that suggested only values between 1970 and 2038 would be allowed, which was never enforced properly though, and only applied in certain column definitions (signed integer, stripping negative values). Instead, better use the TCA type='number', and set TCA restrictions for range.lower=1970 and range.upper=2038 (or any other number) values, see range. This type will then already ensure only numbers can be picked.

MyVendor\MyExtension\*
User defined form evaluations.
fieldControl

For details see fieldControl.

fieldInformation

For details see fieldInformation.

fieldWizard
defaultLanguageDifferences
Type
array
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['fieldWizard']['defaultLanguageDifferences']

For details see defaultLanguageDifferences.

localizationStateSelector
Type
array
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['fieldWizard']['localizationStateSelector']

For details see localizationStateSelector.

otherLanguageContent
Type
array
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['fieldWizard']['otherLanguageContent']

For details see otherLanguageContent.

is_in
Type
string
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['is_in']
Scope
Display / Proc.

If the evaluation type "is_in" (see eval) is used for evaluation, then the characters in the input string should be found in this string as well. This value is also passed as argument to the evaluation function if a user-defined evaluation function is registered.

max
Type
integer
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['max']
Scope
Display

Value for the "maxlength" attribute of the <input> field. Javascript prevents adding more than these number of characters.

If the form element edits a varchar(40) field in the database you should also set this value to 40.

min
Type
integer
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['min']
Scope
Display

This option allows to define a minimum number of characters for the <input> field and adds a minlength attribute to the field. If at least one character is typed in and the number of characters is less than min, the FormEngine marks the field as invalid, preventing the user to save the element. DataHandler will also take care for server-side validation and reset the value to an empty string, if min is not reached.

When using min in combination with max, one has to make sure, the min value is less than or equal max. Otherwise the option is ignored.

Empty fields are not validated. If one needs to have non-empty values, it is recommended to use required => true in combination with min.

mode
Type
string (keywords)
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['mode']
Scope
Display

Possible keywords: useOrOverridePlaceholder

This property is related to the placeholder property. When defined, a checkbox will appear above the field. If that box is checked, the field can be used to enter whatever the user wants as usual. If the box is not checked, the field becomes read-only and the value saved to the database will be NULL .

nullable
Type
boolean
Default
false
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['nullable']
Scope
Proc.

If set to true, a checkbox will appear, which by default deactivates the field. In the deactivated state the field is saved as NULL in the database. By activating the checkbox it is possible to set a value. If nothing is entered into the field, then an empty string will be saved and not a NULL .

The database field must allow the NULL value.

Example: A short title that is NULL unless set
EXT:my_extension/Configuration/TCA/Overrides/106-tx_myextension_conference-short_title.php
<?php

use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

defined('TYPO3') or die();

ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
  'short_title' => [
    'label' => 'my_extension.db:conference.short_title',
    'config' => [
      'type' => 'input',
      'max' => 50,
      'placeholder' => '__row|title',
      'nullable' => true,
      'default' => null,
      'mode' => 'useOrOverridePlaceholder',
      'behaviour' => [
        'allowLanguageSynchronization' => true,
      ],
    ],
  ],
]);
ExtensionManagementUtility::addToAllTCAtypes(
  'tx_myextension_conference',
  'short_title',
  '',
  'after:title',
);
Copied!
placeholder
Type
string
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['placeholder']
Scope
Display

Placeholder, containing a default value.

EXT:my_extension/Configuration/TCA/Overrides/106-tx_myextension_conference-short_title.php
<?php

use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

defined('TYPO3') or die();

ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
  'short_title' => [
    'label' => 'my_extension.db:conference.short_title',
    'config' => [
      'type' => 'input',
      'max' => 50,
      'placeholder' => '__row|title',
      'nullable' => true,
      'default' => null,
      'mode' => 'useOrOverridePlaceholder',
      'behaviour' => [
        'allowLanguageSynchronization' => true,
      ],
    ],
  ],
]);
ExtensionManagementUtility::addToAllTCAtypes(
  'tx_myextension_conference',
  'short_title',
  '',
  'after:title',
);
Copied!
readOnly
Type
boolean
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['readOnly']
Scope
Display

Renders the field in a way that the user can see the value but cannot edit it.

required
Type
boolean
Default
false
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['required']
Scope
Display / Proc.

If set to true a non-empty value is required in the field. Otherwise the form cannot be saved.

Changed in version 14.0 Breaking: #106976 - Removal of TCA search field configuration options

The following TCA field level search configuration options have been removed:

  • search.case
  • search.pidonly
  • search.andWhere

They have not been supported by the Core or common Extensions.

searchable
Type
boolean
Default
true
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['searchable']
Scope
Display

New in version 14.0

TYPO3 now automatically includes all fields of suitable types in backend search operations in the Content > Records module.

This option can be used to explicitly exclude fields from being searchable, instead of having to list them in the now removed option $GLOBALS['TCA'][$table]['ctrl']['searchFields'].

By default, all fields of type input are considered searchable. To exclude a field from being searchable, set the following in the field's TCA configuration:

'searchable' => false,
Copied!
size
Type
integer
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['size']
Scope
Display

Abstract value for the width of the <input> field. To set the input field to the full width of the form area, use the value 50. Minimum is 10. Default is 30.

softref
Type
string
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['softref']
Scope
Proc.
Types
input

Used to attach "soft reference parsers".

The syntax for this value is key1,key2[parameter1;parameter2;...],...

See Soft references of core API for more details about softref keys.

valuePicker
Type
array
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['valuePicker']
Scope
Display

Renders a select box with static values next to the input field. When an item is selected, the value replaces the current input value.

Changed in version 14.0 Breaking: #107677 - Drop prepend and append modes from TCA value picker

The mode option no longer supports append or prepend. Value Picker always behaves like a replace operation. Any legacy mode setting is ignored.

It is now recommended to define associative array keys for the items configuration of the TCA configuration valuePicker. The recommended keys are: label and value. Existing numeric array configurations will be automatically migrated to the new associative format during TCA processing.

items (array)
A list of selectable items. Each item should be an associative array: ['label' => 'Shown label', 'value' => 'storedValue']. The label can be plain text or a label reference.
Example: The rooms of the venue to choose from
EXT:my_extension/Configuration/TCA/tx_myextension_talk.php
<?php

return [
  'ctrl' => [
    'title' => 'my_extension.db:talk',
    'label' => 'title',
    'type' => 'talk_type',
    'typeicon_column' => 'talk_type',
    'typeicon_classes' => [
      'default' => 'my-extension-talk',
      'workshop' => 'my-extension-talk-workshop',
      'keynote' => 'my-extension-talk-keynote',
    ],
    'sortby' => 'sorting',
    'useColumnsForDefaultValues' => 'talk_type,room',
    'hideTable' => true,
    'tstamp' => 'tstamp',
    'crdate' => 'crdate',
    'delete' => 'deleted',
    'enablecolumns' => [
      'disabled' => 'hidden',
    ],
    'languageField' => 'sys_language_uid',
    'transOrigPointerField' => 'l10n_parent',
    'versioningWS' => true,
  ],
  'columns' => [
    'talk_type' => [
      'label' => 'my_extension.db:talk.talk_type',
      'config' => [
        'type' => 'select',
        'renderType' => 'selectSingle',
        'items' => [
          [
            'label' => 'my_extension.db:talk.talk_type.talk',
            'value' => 'talk',
          ],
          [
            'label' => 'my_extension.db:talk.talk_type.workshop',
            'value' => 'workshop',
          ],
          [
            'label' => 'my_extension.db:talk.talk_type.keynote',
            'value' => 'keynote',
          ],
        ],
        'default' => 'talk',
      ],
    ],
    'title' => [
      'label' => 'my_extension.db:talk.title',
      'config' => [
        'type' => 'input',
        'required' => true,
      ],
    ],
    'room' => [
      'label' => 'my_extension.db:talk.room',
      'config' => [
        'type' => 'input',
        'valuePicker' => [
          'items' => [
            ['label' => 'Main hall', 'value' => 'Main hall'],
            ['label' => 'Room A', 'value' => 'Room A'],
            ['label' => 'Room B', 'value' => 'Room B'],
          ],
        ],
      ],
    ],
  ],
  'types' => [
    'talk' => [
      'showitem' => '
        talk_type, title, room,
        --div--;core.form.tabs:access, hidden,
      ',
    ],
    'workshop' => [
      'showitem' => '
        talk_type, title, room,
        --div--;core.form.tabs:access, hidden,
      ',
    ],
    'keynote' => [
      'showitem' => '
        talk_type, title, room,
        --div--;core.form.tabs:access, hidden,
      ',
    ],
  ],
];
Copied!

Input fields with eval 

Trim white space 

Trimming the value for white space before storing in the database:

EXT:my_extension/Configuration/TCA/tx_myextension_conference.php
<?php

return [
  'ctrl' => [
    'title' => 'my_extension.db:conference',
    'label' => 'title',
    'descriptionColumn' => 'internal_notes',
    'default_sortby' => 'conference_date DESC',
    'tstamp' => 'tstamp',
    'crdate' => 'crdate',
    'delete' => 'deleted',
    'editlock' => 'editlock',
    'enablecolumns' => [
      'disabled' => 'hidden',
      'starttime' => 'starttime',
      'endtime' => 'endtime',
      'fe_group' => 'fe_group',
    ],
    'languageField' => 'sys_language_uid',
    'transOrigPointerField' => 'l10n_parent',
    'transOrigDiffSourceField' => 'l10n_diffsource',
    'translationSource' => 'l10n_source',
    'versioningWS' => true,
    'origUid' => 't3_origuid',
    'iconfile' => 'EXT:my_extension/Resources/Public/Icons/Conference.svg',
    'security' => [
      'ignorePageTypeRestriction' => true,
    ],
  ],
  'columns' => [
    'title' => [
      'label' => 'my_extension.db:conference.title',
      'config' => [
        'type' => 'input',
        'required' => true,
        'max' => 255,
        'eval' => 'trim',
      ],
    ],
    'conference_date' => [
      'label' => 'my_extension.db:conference.conference_date',
      'config' => [
        'type' => 'datetime',
        'format' => 'date',
        'required' => true,
      ],
    ],
    'internal_notes' => [
      'label' => 'my_extension.db:conference.internal_notes',
      'config' => [
        'type' => 'text',
        'rows' => 3,
      ],
    ],
  ],
  // The fields of the other tabs are added in Configuration/TCA/Overrides/
  'types' => [
    '0' => [
      'showitem' => '
        title, conference_date,
        --div--;my_extension.db:tab.program,
        --div--;my_extension.db:tab.details,
        --div--;core.form.tabs:categories,
        --div--;core.form.tabs:access,
          hidden, --palette--;;access, fe_group, editlock,
        --div--;core.form.tabs:language,
          --palette--;;language,
        --div--;my_extension.db:tab.comments,
        --div--;core.form.tabs:notes,
          internal_notes,
      ',
    ],
  ],
  'palettes' => [
    'access' => [
      'label' => 'core.form.palettes:access',
      'showitem' => 'starttime, endtime',
    ],
    'language' => [
      'showitem' => 'sys_language_uid, l10n_parent',
    ],
  ],
];
Copied!

Combine eval rules 

TYPO3 removes all space characters from the hashtag of a conference and converts it to lowercase. On the server, TYPO3 also checks that no other conference uses the same hashtag:

EXT:my_extension/Configuration/TCA/Overrides/107-tx_myextension_conference-hashtag.php
<?php

use MyVendor\MyExtension\Evaluation\HashtagEvaluation;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

defined('TYPO3') or die();

ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
  'hashtag' => [
    'label' => 'my_extension.db:conference.hashtag',
    'l10n_mode' => 'exclude',
    'config' => [
      'type' => 'input',
      'max' => 50,
      'eval' => 'trim,nospace,lower,unique,' . HashtagEvaluation::class,
    ],
  ],
]);
ExtensionManagementUtility::addToAllTCAtypes(
  'tx_myextension_conference',
  'hashtag',
  '',
  'after:slug',
);
Copied!

Custom eval rules 

You can supply own form evaluations in an extension by creating a class with three functions, one which returns the JavaScript code for client side validation called returnFieldJS() and two for the server side: deevaluateFieldValue() called when opening the record and evaluateFieldValue() called for validation when saving the record.

The hashtag of a conference uses a class which removes a leading # that editors often type:

EXT:my_extension/Classes/Evaluation/HashtagEvaluation.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Evaluation;

use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction;

/**
 * Removes the leading "#" a hashtag is often entered with
 */
final class HashtagEvaluation
{
  /**
   * Client side: the JavaScript module that evaluates the field
   */
  public function returnFieldJS(): JavaScriptModuleInstruction
  {
    return JavaScriptModuleInstruction::create(
      '@myvendor/my-extension/hashtag-evaluation.js',
      'FormEngineEvaluation',
    );
  }

  /**
   * Server side: evaluates the value before it is saved
   */
  public function evaluateFieldValue(string $value): string
  {
    return ltrim($value, '#');
  }

  /**
   * Server side: prepares the value for the form
   */
  public function deevaluateFieldValue(array $parameters): string
  {
    return (string)$parameters['value'];
  }
}
Copied!

Register the class in ext_localconf.php:

EXT:my_extension/ext_localconf.php
<?php

use MyVendor\MyExtension\Controller\ConferenceController;
use MyVendor\MyExtension\Evaluation\AbstractEvaluation;
use MyVendor\MyExtension\Evaluation\HashtagEvaluation;
use MyVendor\MyExtension\Form\Element\BadgeNameElement;
use MyVendor\MyExtension\Form\FieldInformation\InformationText;
use MyVendor\MyExtension\Form\FieldInformation\TalkOrderInformation;
use MyVendor\MyExtension\Form\FieldWizard\ReferencesToThisRecordWizard;
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;

defined('TYPO3') or die();

ExtensionUtility::configurePlugin(
  'MyExtension',
  'ConferenceList',
  [ConferenceController::class => ['list', 'show']],
);

// Classes that TCA fields name in 'eval'
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][HashtagEvaluation::class] = '';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][AbstractEvaluation::class] = '';

// The information above the talks of a conference, see
// Configuration/TCA/Overrides/120-tx_myextension_conference-talks.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791234567] = [
  'nodeName' => 'talkOrderInformation',
  'priority' => 30,
  'class' => TalkOrderInformation::class,
];

// The badge name of a frontend user, see
// Configuration/TCA/Overrides/650-fe_users-tx_myextension_badge_name.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791300000] = [
  'nodeName' => 'badgeName',
  'priority' => 40,
  'class' => BadgeNameElement::class,
];

// The information text of fields, see for example
// Configuration/TCA/Overrides/310-tx_myextension_speaker-email.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791310000] = [
  'nodeName' => 'informationText',
  'priority' => 30,
  'class' => InformationText::class,
];

// The references to a conference above its form, see
// Configuration/TCA/Overrides/101-tx_myextension_conference-references.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791320000] = [
  'nodeName' => 'referencesToThisRecord',
  'priority' => 30,
  'class' => ReferencesToThisRecordWizard::class,
];
Copied!

returnFieldJS() names a JavaScript module, which removes the # already while the editor types:

EXT:my_extension/Resources/Public/JavaScript/hashtag-evaluation.js
import FormEngineValidation from '@typo3/backend/form-engine-validation.js';

/**
 * Removes the leading "#" of a hashtag while the editor types,
 * like HashtagEvaluation::evaluateFieldValue() does on saving
 */
export class FormEngineEvaluation {
  static registerCustomEvaluation(name) {
    FormEngineValidation.registerCustomEvaluation(name, FormEngineEvaluation.evaluateHashtag);
  }

  static evaluateHashtag(value) {
    return value.replace(/^#+/, '');
  }
}
Copied!

Make the module available in Configuration/JavaScriptModules.php:

EXT:my_extension/Configuration/JavaScriptModules.php
<?php

return [
  'dependencies' => [
    'backend',
  ],
  'imports' => [
    '@myvendor/my-extension/' => 'EXT:my_extension/Resources/Public/JavaScript/',
  ],
];
Copied!

The field names the class in eval:

EXT:my_extension/Configuration/TCA/Overrides/107-tx_myextension_conference-hashtag.php
<?php

use MyVendor\MyExtension\Evaluation\HashtagEvaluation;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

defined('TYPO3') or die();

ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
  'hashtag' => [
    'label' => 'my_extension.db:conference.hashtag',
    'l10n_mode' => 'exclude',
    'config' => [
      'type' => 'input',
      'max' => 50,
      'eval' => 'trim,nospace,lower,unique,' . HashtagEvaluation::class,
    ],
  ],
]);
ExtensionManagementUtility::addToAllTCAtypes(
  'tx_myextension_conference',
  'hashtag',
  '',
  'after:slug',
);
Copied!