---
title: "PSR-14 Events"
manual: "Form"
version: "14.3"
permalink: "https://docs.typo3.org/permalink/typo3/cms-form:apireference-frontendrendering-runtimemanipulation-hooks-beforerendering-use@14.3"
source: "D/Events/Index.rst"
rendered: "2026-09-19T11:59:02+00:00"
---

# PSR-14 Events {#apireference-frontendrendering-runtimemanipulation-hooks-beforerendering-use}

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.

> [!NOTE]
> **See also**
>
> The canonical, always-up-to-date reference for all EXT:form events lives
> in the TYPO3 Core API documentation:
>
> [Form](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Events/Events/Form/Index.html#eventlist-form)
>
> The extension documentation below provides context, usage notes and
> quick navigation; it intentionally avoids duplicating the full API
> reference.

-   [Backend events (form editor / manager)](https://docs.typo3.org/permalink/typo3/cms-form:backend-events-form-editor-manager@14.3)
-   [Frontend events (form rendering / runtime)](https://docs.typo3.org/permalink/typo3/cms-form:frontend-events-form-rendering-runtime@14.3)
-   [Registering an event listener](https://docs.typo3.org/permalink/typo3/cms-form:registering-an-event-listener@14.3)
-   [Legacy hooks (still supported)](https://docs.typo3.org/permalink/typo3/cms-form:legacy-hooks-still-supported@14.3)

## Backend events (form editor / manager) {#apireference-events-backend}

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](https://docs.typo3.org/permalink/t3coreapi:beforeformiscreatedevent) | Modify the form definition array and/or the persistence identifier before a new form is created in the backend. |
| [BeforeFormIsSavedEvent](https://docs.typo3.org/permalink/t3coreapi:beforeformissavedevent) | Modify the form definition array and/or the persistence identifier before a form is saved in the backend. |
| [BeforeFormIsDuplicatedEvent](https://docs.typo3.org/permalink/t3coreapi:beforeformisduplicatedevent) | Modify the form definition array and/or the persistence identifier of the copy before a form is duplicated. |
| [BeforeFormIsDeletedEvent](https://docs.typo3.org/permalink/t3coreapi:beforeformisdeletedevent) | Dispatched before a form is deleted. Set `$event->preventDeletion = true` to abort the deletion (the event implements `StoppableEventInterface`). |

## Frontend events (form rendering / runtime) {#apireference-events-frontend}

These events are dispatched during form rendering in the frontend.

| Event | When / what can be modified |
| --- | --- |
| [AfterFormIsBuiltEvent](https://docs.typo3.org/permalink/t3coreapi:afterformisbuiltevent) | Modify the `FormDefinition` object after the form factory has finished building the complete form. |
| [BeforeRenderableIsAddedToFormEvent](https://docs.typo3.org/permalink/t3coreapi:beforerenderableisaddedtoformevent) | Modify or replace a renderable (page, section or element) before it is added to the form tree. |
| [BeforeRenderableIsRemovedFromFormEvent](https://docs.typo3.org/permalink/t3coreapi:beforerenderableisremovedfromformevent) | Dispatched before a renderable is removed from the form tree. Set `$event->preventRemoval = true` to abort the removal (the event implements `StoppableEventInterface`). |
| [AfterCurrentPageIsResolvedEvent](https://docs.typo3.org/permalink/t3coreapi:aftercurrentpageisresolvedevent) | Override `$event->currentPage` after the current page has been resolved from the request, e.g. to implement conditional page-skip logic. |
| [BeforeRenderableIsValidatedEvent](https://docs.typo3.org/permalink/t3coreapi:beforerenderableisvalidatedevent) | Modify `$event->value` before property-mapping and validation run for each submitted form element. |
| [BeforeRenderableIsRenderedEvent](https://docs.typo3.org/permalink/t3coreapi:beforerenderableisrenderedevent) | Modify the renderable or the `FormRuntime` just before a renderable is output to the browser. |
| [BeforeEmailFinisherInitializedEvent](https://docs.typo3.org/permalink/t3coreapi:beforeemailfinisherinitializedevent) | Modify the options used by the `EmailFinisher` (e.g. recipients, subject) before they are applied. |
| [AfterFormDefinitionLoadedEvent](https://docs.typo3.org/permalink/t3coreapi: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 {#apireference-events-register}

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

**EXT:my_extension/Classes/EventListener/MyFormEventListener.php**

```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';
    }
}

```

> [!NOTE]
> **See also**
>
> [Event dispatcher (PSR-14 events)](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Events/EventDispatcher/Index.html#EventDispatcher) – TYPO3 Core API documentation on how to
> register and implement PSR-14 event listeners.

## Legacy hooks (still supported) {#apireference-events-legacy-hooks}

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 {#apireference-events-legacy-hooks-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
<?php

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['afterFormStateInitialized'][1700000000]
    = \MyVendor\MyExtension\Hooks\MyAfterFormStateInitializedHook::class;

```

**EXT:my_extension/Classes/Hooks/MyAfterFormStateInitializedHook.php**

```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
    }
}

```

### buildFormDefinitionValidationConfiguration {#apireference-events-legacy-hooks-buildformvalidationconfiguration}

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
<?php

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['buildFormDefinitionValidationConfiguration'][]
    = \MyVendor\MyExtension\Hooks\MyValidationConfigurationHook::class;

```

**EXT:my_extension/Classes/Hooks/MyValidationConfigurationHook.php**

```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'),
        ];
    }
}

```
