PSR-14 Events 

EXT:form dispatches PSR-14 events at key points in the lifecycle of a form – both in the backend form editor and during frontend rendering. These events are the recommended extension point for developers; the legacy $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'] hooks have been removed.

Backend events (form editor / manager) 

These events are dispatched when an editor creates, saves, duplicates or deletes a form definition in the TYPO3 backend.

Event When / what can be modified
BeforeFormIsCreatedEvent Modify the form definition array and/or the persistence identifier before a new form is created in the backend.
BeforeFormIsSavedEvent Modify the form definition array and/or the persistence identifier before a form is saved in the backend.
BeforeFormIsDuplicatedEvent Modify the form definition array and/or the persistence identifier of the copy before a form is duplicated.
BeforeFormIsDeletedEvent Dispatched before a form is deleted. Set $event->preventDeletion = true to abort the deletion (the event implements StoppableEventInterface).

Frontend events (form rendering / runtime) 

These events are dispatched during form rendering in the frontend.

Event When / what can be modified
AfterFormIsBuiltEvent Modify the FormDefinition object after the form factory has finished building the complete form.
BeforeRenderableIsAddedToFormEvent Modify or replace a renderable (page, section or element) before it is added to the form tree.
BeforeRenderableIsRemovedFromFormEvent Dispatched before a renderable is removed from the form tree. Set $event->preventRemoval = true to abort the removal (the event implements StoppableEventInterface).
AfterCurrentPageIsResolvedEvent Override $event->currentPage after the current page has been resolved from the request, e.g. to implement conditional page-skip logic.
BeforeRenderableIsValidatedEvent Modify $event->value before property-mapping and validation run for each submitted form element.
BeforeRenderableIsRenderedEvent Modify the renderable or the FormRuntime just before a renderable is output to the browser.
BeforeEmailFinisherInitializedEvent Modify the options used by the EmailFinisher (e.g. recipients, subject) before they are applied.
AfterFormDefinitionLoadedEvent Dispatched by FormPersistenceManager after a YAML form definition has been loaded from disk. Modify the definition globally before it reaches the form factory.

Registering an event listener 

Register a listener via the #[AsEventListener] PHP attribute:

EXT:my_extension/Classes/EventListener/MyFormEventListener.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\EventListener;

use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Form\Event\BeforeFormIsSavedEvent;

#[AsEventListener(
    identifier: 'my-extension/before-form-is-saved',
)]
final readonly class MyFormEventListener
{
    public function __invoke(BeforeFormIsSavedEvent $event): void
    {
        // Enrich the form definition before it is persisted
        $event->form['renderingOptions']['myCustomOption'] = 'value';
    }
}
Copied!

Legacy hooks (still supported) 

The following $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'] hooks are still active in the current codebase. They have not yet been replaced by PSR-14 events. Avoid using them in new code if a PSR-14 alternative exists.

afterFormStateInitialized 

Dispatched by FormRuntime after the FormState has been restored from the request. At this point both the form state (submitted values) and the static form definition are available, which makes it suitable for enriching components that need runtime data.

Implement \TYPO3\CMS\Form\Domain\Runtime\FormRuntime\Lifecycle\AfterFormStateInitializedInterface and register the class:

EXT:my_extension/ext_localconf.php
<?php

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['afterFormStateInitialized'][1700000000]
    = \MyVendor\MyExtension\Hooks\MyAfterFormStateInitializedHook::class;
Copied!
EXT:my_extension/Classes/Hooks/MyAfterFormStateInitializedHook.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Hooks;

use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
use TYPO3\CMS\Form\Domain\Runtime\FormRuntime\Lifecycle\AfterFormStateInitializedInterface;

final class MyAfterFormStateInitializedHook implements AfterFormStateInitializedInterface
{
    public function afterFormStateInitialized(FormRuntime $formRuntime): void
    {
        // Access $formRuntime->getFormState() here
    }
}
Copied!

buildFormDefinitionValidationConfiguration 

Used when a custom form editor inspector editor does not declare its writable property paths via the standard YAML configuration (e.g. propertyPath). Implement addAdditionalPropertyPaths() to return additional ValidationDto objects that tell the backend form editor which properties may be written.

Register the hook class:

EXT:my_extension/ext_localconf.php
<?php

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['buildFormDefinitionValidationConfiguration'][]
    = \MyVendor\MyExtension\Hooks\MyValidationConfigurationHook::class;
Copied!
EXT:my_extension/Classes/Hooks/MyValidationConfigurationHook.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Hooks;

use TYPO3\CMS\Form\Domain\Configuration\FormDefinition\Validators\ValidationDto;

final class MyValidationConfigurationHook
{
    /**
     * @return ValidationDto[]
     */
    public function addAdditionalPropertyPaths(ValidationDto $validationDto): array
    {
        $textDto = $validationDto->withFormElementType('Text');
        return [
            $textDto->withPropertyPath('properties.my.custom.property'),
        ];
    }
}
Copied!