JavaScript events 

The form editor uses a publish/subscribe bus for all cross-component communication. Any custom JavaScript module can subscribe to these events to extend or react to editor behaviour without patching core files.

Publish / subscribe basics 

Subscribe to an event
export function bootstrap(formEditorApp) {
    const ps = formEditorApp.getPublisherSubscriber();

    // Subscribe – returns a token for later unsubscription
    const token = ps.subscribe('view/ready', (topic, args) => {
        // args is a typed tuple matching the event signature
    });

    // Unsubscribe
    ps.unsubscribe(token);
}
Copied!
Publish a custom event from within your module
export function bootstrap(formEditorApp) {
    formEditorApp.getPublisherSubscriber().publish('my/custom/event', ['arg1', 'arg2']);
}
Copied!

Event quick-reference 

Lifecycle 

Event When it fires
view/ready All modules loaded; editor is fully initialised.

Ajax / data transfer 

Event When it fires
core/ajax/saveFormDefinition/success Form definition saved successfully.
core/ajax/saveFormDefinition/error Server returned an error while saving.
core/ajax/renderFormDefinitionPage/success Preview HTML for the current page returned successfully.
core/ajax/error Any Ajax request (save or preview render) failed.

Application state 

Event When it fires
core/applicationState/add Undo/redo stack was updated.
core/currentlySelectedFormElementChanged The currently selected form element changed.
core/formElement/somePropertyChanged A property was written to a FormElement model via set().

Form element lifecycle 

Event When it fires
view/formElement/inserted A new form element was added to the tree.
view/formElement/moved A form element was moved within the tree.
view/formElement/removed A form element was deleted.

Collection elements (validators / finishers) 

Event When it fires
view/collectionElement/new/added A validator or finisher was added.
view/collectionElement/moved A validator or finisher was reordered.
view/collectionElement/removed A validator or finisher was removed.

Insert element / page dialogs 

Event When it fires
view/insertElements/perform/before Insert new element before the selected one.
view/insertElements/perform/after Insert new element after the selected one.
view/insertElements/perform/inside Insert new element inside the selected composite.
view/insertElements/perform/bottom Insert new element at the end of the current page.
view/insertPages/perform Insert a new page after the current one.

Header buttons 

Event When it fires
view/header/button/save/clicked "Save" button clicked.
view/header/button/close/clicked "Close" button clicked (with unsaved changes guard).
view/header/button/newPage/clicked "New page" button clicked.
view/header/formSettings/clicked "Form settings" button clicked.
view/undoButton/clicked Undo button clicked.
view/redoButton/clicked Redo button clicked.
view/viewModeButton/abstract/clicked "Abstract view" toggle clicked.
view/viewModeButton/preview/clicked "Preview" toggle clicked.
view/paginationNext/clicked "Next page" pagination button clicked.
view/paginationPrevious/clicked "Previous page" pagination button clicked.

Stage 

Event When it fires
view/stage/abstract/render/template/perform Main extension point. Stage renders a form element that has a formEditorPartials entry.
view/stage/abstract/render/preProcess Before the abstract stage area is rendered.
view/stage/abstract/render/postProcess After the abstract stage area was rendered.
view/stage/preview/render/postProcess After the preview stage area was rendered.
view/stage/element/clicked A form element in the stage was clicked.
view/stage/panel/clicked The stage panel background was clicked.
view/stage/abstract/button/newElement/clicked "Add element" button at the bottom of the stage clicked.
view/stage/abstract/elementToolbar/button/newElement/clicked Toolbar "add element" / split button on an element clicked.
view/stage/abstract/dnd/start Drag started in the stage.
view/stage/abstract/dnd/change Drag position changed in the stage.
view/stage/abstract/dnd/update Drag ended, model position updated.
view/stage/abstract/dnd/stop Drag operation finished.

Inspector 

Event When it fires
view/inspector/editor/insert/perform Extension point for custom inspector editors.
view/inspector/collectionElement/new/selected A new validator/finisher was chosen in the select box.
view/inspector/collectionElement/existing/selected An existing validator/finisher section was expanded.
view/inspector/collectionElements/dnd/update A validator/finisher was reordered via drag-and-drop.
view/inspector/removeCollectionElement/perform Remove a validator/finisher (from RequiredValidatorEditor checkbox).

Structure tree 

Event When it fires
view/structure/root/selected Root element in the tree was clicked.
view/structure/button/newPage/clicked "New page" button in the tree panel clicked.
view/structure/renew/postProcess Tree was re-rendered.
view/tree/node/clicked A tree node was clicked.
view/tree/node/changed A tree node label was edited inline.
view/tree/render/listItemAdded Reserved – not yet published by core. (A list item was added to the tree.)
view/tree/dnd/change Drag position changed in the tree.
view/tree/dnd/update Drag ended, model position updated.
view/tree/dnd/stop Drag operation finished.

Dialogs (modals) 

Event When it fires
view/modal/close/perform User confirmed closing the editor with unsaved changes.
view/modal/removeFormElement/perform User confirmed deleting a form element.
view/modal/removeCollectionElement/perform User confirmed removing a validator/finisher.
view/modal/validationErrors/element/clicked A form element was clicked in the validation-error dialog.

Event reference 

view/ready 

Published once all additional view-model modules registered via dynamicJavaScriptModules.additionalViewModelModules have bootstrapped. EXT:form uses this event to remove the loading indicator and finish editor initialisation. This is the earliest safe point to interact with the fully wired editor.

Arguments

none

export function bootstrap(formEditorApp) {
    formEditorApp.getPublisherSubscriber().subscribe('view/ready', () => {
        // Safe to call any formEditorApp API here.
    });
}
Copied!

core/ajax/saveFormDefinition/success 

Published after the form definition was saved successfully. EXT:form shows a success flash message, updates the in-memory form definition and re-renders all components.

Arguments
 
Index Type Description
args[0] { status: string, formDefinition: object } Response payload; formDefinition is the saved definition.

core/ajax/saveFormDefinition/error 

Published when the save Ajax request returns a server-side error.

Arguments
 
Index Type Description
args[0] { status: string, message: string, code: number } Error details from the server.

core/ajax/renderFormDefinitionPage/success 

Published after the preview Ajax request returns successfully. EXT:form uses this to display the rendered form HTML in the preview stage.

Arguments
 
Index Type Description
args[0] string Rendered HTML of the current form page.
args[1] number Zero-based index of the rendered page.

core/ajax/error 

Published when any Ajax request (save or preview render) fails at the HTTP level. EXT:form shows an error flash message and displays the raw error in the preview area.

Arguments
 
Index Type Description
args[0] string HTTP status text (e.g. 'Internal Server Error').
args[1] string Raw response body.

core/applicationState/add 

Published every time an action (add / remove / move element or collection element) is pushed onto the undo/redo stack. EXT:form uses this to enable or disable the undo/redo buttons.

Arguments
 
Index Type Description
args[0] ApplicationState Snapshot of the application state that was just pushed.
args[1] number Current stack pointer position (0-based).
args[2] number Total number of entries in the undo/redo stack.

core/currentlySelectedFormElementChanged 

Published at the end of formEditorApp.setCurrentlySelectedFormElement(). All components that need to react to a selection change (inspector, stage, tree highlight) subscribe to this event.

Arguments
 
Index Type Description
args[0] FormElement The newly selected FormElement model.

core/formElement/somePropertyChanged 

Published by the FormElement model whenever a property is written via set(). EXT:form uses this to keep the tree labels, stage and inspector in sync. It is also the mechanism behind FormElement.on().

Arguments
 
Index Type Description
args[0] string Dot-separated property path that was written.
args[1] unknown New value.
args[2] unknown Previous value.
args[3] string | undefined __identifierPath of the element whose property changed.
export function bootstrap(formEditorApp) {
    formEditorApp.getPublisherSubscriber().subscribe(
        'core/formElement/somePropertyChanged',
        (topic, args) => {
            const [propertyPath, newValue, oldValue, identifierPath] = args;
            if (propertyPath === 'label' && identifierPath?.startsWith('my-form/page-1/')) {
                console.log('Label changed from', oldValue, 'to', newValue);
            }
        },
    );
}
Copied!

view/formElement/inserted 

Published after a new form element has been added to the form definition tree. EXT:form selects the new element and re-renders tree, stage and inspector.

Arguments
 
Index Type Description
args[0] FormElement The newly inserted FormElement model.

view/formElement/moved 

Published after a form element has been moved within the tree. EXT:form does not add additional behaviour here by default.

Arguments
 
Index Type Description
args[0] FormElement The moved FormElement model.

view/formElement/removed 

Published after a form element has been removed. EXT:form selects the parent element and re-renders tree, stage and inspector.

Arguments
 
Index Type Description
args[0] FormElement The parent FormElement model of the deleted element.

view/collectionElement/new/added 

Published after a new validator or finisher has been created and added to the form definition. EXT:form re-renders the inspector.

Arguments
 
Index Type Description
args[0] string Identifier of the new collection element (e.g. 'NotEmpty').
args[1] string Collection name: 'validators' or 'finishers'.
args[2] FormElement The owning form element.
args[3] object Full configuration object of the added collection element.
args[4] string Identifier of the reference element (inserted before/after).

view/collectionElement/moved 

Published after a validator or finisher has been reordered. EXT:form re-renders the inspector.

Arguments
 
Index Type Description
args[0] string Identifier of the moved element.
args[1] string Relative position: 'before' or 'after'.
args[2] string Identifier of the reference element.
args[3] string Collection name.
args[4] FormElement The owning form element.

view/collectionElement/removed 

Published after a validator or finisher has been removed from the form definition. EXT:form re-renders the inspector.

Arguments
 
Index Type Description
args[0] string Identifier of the removed element.
args[1] string Collection name.
args[2] FormElement The owning form element.

view/insertElements/perform/before 

Published when the user selects an element type in the "New element" dialog after clicking the "Before" toolbar option. EXT:form creates the new element and moves it before the currently selected element.

Arguments
 
Index Type Description
args[0] string Form element type identifier (e.g. 'Text').

view/insertElements/perform/after 

Published when the user selects an element type after clicking the "After" toolbar option or the standard toolbar button for non-composite elements. EXT:form creates the element and moves it after the selected element (as a sibling).

Arguments
 
Index Type Description
args[0] string Form element type identifier.

view/insertElements/perform/inside 

Published when the user selects an element type after clicking the "Inside" toolbar option on a composite element (e.g. Fieldset). EXT:form creates the element as a child of the currently selected composite.

Arguments
 
Index Type Description
args[0] string Form element type identifier.

view/insertElements/perform/bottom 

Published when the user selects an element type after clicking the "Create new element" button at the very bottom of the stage in abstract view. EXT:form appends the element as the last child of the current page.

Arguments
 
Index Type Description
args[0] string Form element type identifier.

view/insertPages/perform 

Published when the user selects a page type in the "New page" dialog. EXT:form creates the page after the currently selected page.

Arguments
 
Index Type Description
args[0] string Form element type identifier (typically 'Page').

view/header/button/save/clicked 

Published when the "Save" button is clicked. EXT:form either opens a validation-error dialog (if there are errors) or saves the form definition.

Arguments

none

view/header/button/close/clicked 

Published when the "Close" button is clicked and the form has unsaved changes. EXT:form opens a confirmation dialog.

Arguments

none

view/header/button/newPage/clicked 

Published when the "New page" icon in the header is clicked. EXT:form opens the "New page" dialog.

Arguments
 
Index Type Description
args[0] 'view/insertPages/perform' The event to publish once the user picks a page type.

view/header/formSettings/clicked 

Published when the "Form settings" button is clicked. EXT:form selects the root form element and renders its settings in the inspector.

Arguments

none

view/undoButton/clicked 

Published when the undo button is clicked. EXT:form steps back one state in the undo/redo stack and re-renders all components.

Arguments

none

view/redoButton/clicked 

Published when the redo button is clicked. EXT:form steps forward one state in the undo/redo stack and re-renders all components.

Arguments

none

view/viewModeButton/abstract/clicked 

Published when the "Abstract view" toggle in the stage header is clicked. EXT:form switches to abstract view if not already active.

Arguments

none

view/viewModeButton/preview/clicked 

Published when the "Preview" toggle in the stage header is clicked. EXT:form switches to preview view if not already active.

Arguments

none

view/paginationNext/clicked 

Published when the "next page" arrow in the stage header is clicked. EXT:form advances to the next form page.

Arguments

none

view/paginationPrevious/clicked 

Published when the "previous page" arrow in the stage header is clicked. EXT:form goes back to the previous form page.

Arguments

none

view/stage/abstract/render/template/perform 

The primary extension point for custom stage rendering.

Published by the Stage component for each form element that has a formEditorPartials entry in the prototype configuration. Form elements without a formEditorPartials entry are rendered automatically by the <typo3-form-form-element-stage-item> web component — no subscriber is needed for those.

Arguments
 
Index Type Description
args[0] FormElement The FormElement model being rendered.
args[1] HTMLElement Cloned DOM node from the Fluid partial. Populate this via DOM manipulation.

Full example — custom element with a dedicated stage partial:

Fluid partial (EXT:my_extension/Resources/Private/Backend/Partials/FormEditor/Stage/MyCustomElement.html):

<div class="formeditor-element-body">
    <div data-identifier="elementLabel"></div>
    <div data-identifier="elementSummary"></div>
</div>
Copied!

Prototype YAML configuration:

prototypes:
  standard:
    formEditor:
      dynamicJavaScriptModules:
        additionalViewModelModules:
          10: '@vendor/my-extension/backend/form-editor/view-model.js'
      formEditorPartials:
        FormElement-MyCustomElement: 'Stage/MyCustomElement'
      formEditorFluidConfiguration:
        partialRootPaths:
          100: 'EXT:my_extension/Resources/Private/Backend/Partials/FormEditor/'
Copied!

JavaScript module:

EXT:my_extension/Resources/Public/JavaScript/backend/form-editor/view-model.js
export function bootstrap(formEditorApp) {
    formEditorApp.getPublisherSubscriber().subscribe(
        'view/stage/abstract/render/template/perform',
        (topic, args) => {
            const [formElement, template] = args;

            if (formElement.get('type') !== 'MyCustomElement') {
                return;
            }

            const labelEl = template.querySelector('[data-identifier="elementLabel"]');
            if (labelEl) {
                labelEl.textContent =
                    formElement.get('label') || formElement.get('identifier');
            }

            const summaryEl = template.querySelector('[data-identifier="elementSummary"]');
            if (summaryEl) {
                summaryEl.textContent =
                    formElement.get('properties.myCustomProperty') ?? '';
            }
        },
    );
}
Copied!

view/stage/abstract/render/preProcess 

Published immediately before the abstract stage area is re-rendered.

Arguments

none

view/stage/abstract/render/postProcess 

Published immediately after the abstract stage area has been rendered. EXT:form uses this to re-render the undo/redo buttons and apply validation error highlights.

Arguments

none

view/stage/preview/render/postProcess 

Published after the preview stage area has been rendered. EXT:form uses this to re-render the undo/redo buttons.

Arguments

none

view/stage/element/clicked 

Published when a form element in the abstract stage is clicked. EXT:form selects the element, shows its toolbar and re-renders the inspector.

Arguments
 
Index Type Description
args[0] string __identifierPath of the clicked element.

view/stage/panel/clicked 

Published when the stage panel header or background area is clicked (not on a specific form element).

Arguments

none

view/stage/abstract/button/newElement/clicked 

Published when the "Create new element" button at the bottom of the stage (in abstract view) is clicked. EXT:form opens the "New element" dialog configured to insert at the bottom of the current page.

Arguments
 
Index Type Description
args[0] 'view/insertElements/perform/bottom' Target publish event for the dialog result.
args[1] object | undefined Optional modal configuration.

view/stage/abstract/elementToolbar/button/newElement/clicked 

Published when the "Add element" button or split-button ("Before", "After", "Inside") in the per-element toolbar is clicked. EXT:form opens the "New element" dialog with the appropriate target event.

Arguments
 
Index Type Description
args[0] string Target event: 'view/insertElements/perform/before', '…/after' or '…/inside'.
args[1] object Modal configuration (disableElementTypes, onlyEnableElementTypes).

view/stage/abstract/dnd/start 

Published when a drag operation begins in the abstract stage. EXT:form adds CSS classes to highlight the dragged element.

Arguments
 
Index Type Description
args[0] HTMLElement The dragged element's DOM node.
args[1] HTMLElement The drag placeholder DOM node.

view/stage/abstract/dnd/change 

Published on each positional change during a drag operation in the stage (SortableJS onChange). EXT:form applies hover CSS classes.

Arguments
 
Index Type Description
args[0] HTMLElement The drag placeholder DOM node.
args[1] string __identifierPath of the potential parent element.
args[2] FormElement Innermost enclosing composite element (if any).

view/stage/abstract/dnd/update 

Published at the end of a drag operation when the element was dropped in a new position (SortableJS onEnd). EXT:form calls moveFormElement() to persist the new order.

Arguments
 
Index Type Description
args[0] HTMLElement The dropped DOM node.
args[1] string __identifierPath of the moved element.
args[2] string __identifierPath of the preceding sibling (empty string if first).
args[3] string __identifierPath of the following sibling (empty string if last).

view/stage/abstract/dnd/stop 

Published after the drag operation completes and all model updates are done. EXT:form re-renders tree, stage and inspector and selects the moved element.

Arguments
 
Index Type Description
args[0] string __identifierPath of the element that was dragged.

view/inspector/editor/insert/perform 

Extension point for custom inspector editors.

Published after each inspector editor has been rendered (both for form elements and for collection elements). Use args[0].templateName to identify which editor is being rendered and apply custom logic.

Arguments
 
Index Type Description
args[0] EditorConfiguration Full YAML configuration of the editor (includes templateName).
args[1] HTMLElement The rendered DOM node of the inspector editor.
args[2] string Identifier of the active collection element (validator/finisher), or empty string when rendering a plain element editor.
args[3] string Collection name ('validators' or 'finishers'), or empty.

Example — register a custom inspector editor:

Prototype YAML:

prototypes:
  standard:
    formEditor:
      dynamicJavaScriptModules:
        additionalViewModelModules:
          10: '@vendor/my-extension/backend/form-editor/view-model.js'
      formEditorPartials:
        Inspector-MyCustomEditor: 'Inspector/MyCustomEditor'
      formEditorFluidConfiguration:
        partialRootPaths:
          100: 'EXT:my_extension/Resources/Private/Backend/Partials/FormEditor/'
    formElementsDefinition:
      Text:
        formEditor:
          editors:
            600:
              templateName: 'Inspector-MyCustomEditor'
              myOption: 'example'
Copied!

JavaScript module:

EXT:my_extension/Resources/Public/JavaScript/backend/form-editor/view-model.js
export function bootstrap(formEditorApp) {
    formEditorApp.getPublisherSubscriber().subscribe(
        'view/inspector/editor/insert/perform',
        (topic, args) => {
            const [editorConfiguration, editorHtml] = args;

            if (editorConfiguration.templateName !== 'Inspector-MyCustomEditor') {
                return;
            }

            // Wire up your custom editor UI inside editorHtml
            const input = editorHtml.querySelector('.my-custom-input');
            if (input) {
                input.addEventListener('change', (e) => {
                    formEditorApp
                        .getCurrentlySelectedFormElement()
                        .set(editorConfiguration.propertyPath, e.target.value);
                });
            }
        },
    );
}
Copied!

view/inspector/collectionElement/new/selected 

Published when the user selects a new validator or finisher from the select box in the inspector. EXT:form adds the collection element to the form definition and re-renders the inspector.

Arguments
 
Index Type Description
args[0] string Identifier of the selected collection element.
args[1] string Collection name ('validators' or 'finishers').

view/inspector/collectionElement/existing/selected 

Published when the user expands an existing validator or finisher row in the inspector. EXT:form renders that element's sub-editors.

Arguments
 
Index Type Description
args[0] string Identifier of the already-selected collection element.
args[1] string Collection name.

view/inspector/collectionElements/dnd/update 

Published when a validator or finisher is reordered via drag-and-drop inside the inspector (SortableJS onEnd). EXT:form moves the element in the form definition.

Arguments
 
Index Type Description
args[0] string Identifier of the moved element.
args[1] string Identifier of the preceding element after the move.
args[2] string Identifier of the following element after the move.
args[3] string Collection name.

view/inspector/removeCollectionElement/perform 

Published by the RequiredValidatorEditor when its checkbox is unchecked. EXT:form removes the NotEmpty validator from the form definition.

Arguments
 
Index Type Description
args[0] string Validator identifier (e.g. 'NotEmpty').
args[1] 'validators' Collection name (always 'validators' for this event).
args[2] FormElement | undefined The owning form element, or undefined for the currently selected one.

view/modal/close/perform 

Published when the user confirms closing the editor in the "unsaved changes" dialog. EXT:form clears the unsaved-content flag and navigates back to the form manager.

Arguments

none

view/modal/removeFormElement/perform 

Published when the user confirms deleting a form element in the confirmation dialog. EXT:form removes the element from the form definition.

Arguments
 
Index Type Description
args[0] FormElement The form element to be deleted.

view/modal/removeCollectionElement/perform 

Published when the user confirms removing a validator or finisher via its delete icon. EXT:form removes the collection element from the form definition.

Arguments
 
Index Type Description
args[0] string Identifier of the collection element to remove.
args[1] string Collection name.
args[2] FormElement The owning form element.

view/modal/validationErrors/element/clicked 

Published when the user clicks a form element link inside the validation error dialog. EXT:form selects the element and navigates to it.

Arguments
 
Index Type Description
args[0] string __identifierPath of the element with the validation error.

view/structure/root/selected 

Published when the root element in the structure tree is clicked. EXT:form selects the root form element and re-renders stage, tree and inspector.

Arguments

none

view/structure/button/newPage/clicked 

Published when the "Create new page" button inside the structure tree panel is clicked. EXT:form opens the "New page" dialog.

Arguments
 
Index Type Description
args[0] 'view/insertPages/perform' Target publish event for the dialog result.

view/structure/renew/postProcess 

Published after the structure tree has been fully re-rendered. EXT:form uses this to apply validation error markers to tree nodes.

Arguments

none

view/tree/node/clicked 

Published when a node in the structure tree is clicked. EXT:form selects the element and re-renders stage and inspector.

Arguments
 
Index Type Description
args[0] string __identifierPath of the clicked element.

view/tree/node/changed 

New in version 13.4

This event was previously missing from the documentation. It has been dispatched since inline label editing in the structure tree was introduced.

Published when a tree node label is edited inline (inline-rename). EXT:form writes the new label to the FormElement model and updates the inspector if the element is currently selected.

Arguments
 
Index Type Description
args[0] string __identifierPath of the renamed element.
args[1] string The new label string.

view/tree/render/listItemAdded 

Published by the tree component for each form element as it is added to the rendered tree. Use this to augment individual tree nodes.

Arguments
 
Index Type Description
args[0] HTMLElement | null The list item DOM node that was added.
args[1] FormElement The FormElement model for this tree node.

view/tree/dnd/change 

Published on each positional change during a drag in the structure tree (SortableJS onChange). EXT:form applies hover CSS classes.

Arguments
 
Index Type Description
args[0] HTMLElement | null The drag placeholder node.
args[1] string __identifierPath of the potential parent element.
args[2] FormElement Innermost enclosing composite element (if any).

view/tree/dnd/update 

Published when a drag in the structure tree ends and the element was dropped in a new position. EXT:form calls moveFormElement().

Arguments
 
Index Type Description
args[0] HTMLElement | null The dropped DOM node.
args[1] string __identifierPath of the moved element.
args[2] string __identifierPath of the preceding sibling.
args[3] string __identifierPath of the following sibling.

view/tree/dnd/stop 

Published after the tree drag operation completes. EXT:form re-renders tree, stage and inspector and selects the moved element.

Arguments
 
Index Type Description
args[0] string __identifierPath of the element that was dragged.