Skip to content

Form: FormDefinitionDecorator strictly strips root-level renderingOptions, breaking custom frontend settings #905

Description

@t3brightside

When adding custom configuration toggles to the root Form element (via renderingOptions or properties) in the Form Editor, these values are entirely stripped from the JSON response. The FormDefinitionDecorator hardcodes a strict mapping of allowed root keys (id, api, i18n, elements) and discards root-level renderingOptions.

This prevents integrators from passing form-level configuration (e.g., custom UI flags) to headless frontends.

To Reproduce
Extend the global Form prototype in YAML to add custom fields to the Form Editor under a public namespace (or at root level).

Expected Behavior
The native TYPO3 Form Framework uses renderingOptions to pass configuration to the renderer. The headless extension should support exposing safe, client-facing renderingOptions to the JSON payload so headless frontends (Astro, Next.js, Nuxt, etc.) can react to form-level settings.

Implementation
Directly passing $definition['renderingOptions'] as-is could inadvertently leak sensitive server-side paths (honeypot, Fluid templateRootPaths, finisher internals).

A safe, idiomatic solution for FormDefinitionDecorator::__invoke() would be to adopt a dedicated frontend namespace convention under renderingOptions (alongside safe native root keys like submitButtonLabel), while allowing integrators to flatten it if needed via decorators/events:

Example:

YAML

TYPO3:
  CMS:
    Form:
      prototypes:
        standard:
          formElementsDefinition:
            Form:
              renderingOptions:
                frontend:
                  enableTurnstile: true
              formEditor:
                predefinedDefaults:
                  renderingOptions:
                    frontend:
                      enableTurnstile: true
                editors:
                  700:
                    identifier: enableTurnstile
                    templateName: Inspector-CheckboxEditor
                    label: "Enable Turnstile"
                    propertyPath: renderingOptions.frontend.enableTurnstile

PHP

// In \FriendsOfTYPO3\Headless\Form\Decorator\FormDefinitionDecorator::__invoke()

if (isset($definition['renderingOptions']) && is_array($definition['renderingOptions'])) {
    $renderingOptions = $definition['renderingOptions'];
    $publicRenderingOptions = [];

    // 1. Pass native safe client-facing keys
    $safeNativeKeys = ['submitButtonLabel', 'previousButtonLabel', 'nextButtonLabel'];
    foreach ($safeNativeKeys as $key) {
        if (array_key_exists($key, $renderingOptions)) {
            $publicRenderingOptions[$key] = $renderingOptions[$key];
        }
    }

    // 2. Pass custom frontend-flagged options namespace
    if (isset($renderingOptions['frontend']) && is_array($renderingOptions['frontend'])) {
        $publicRenderingOptions['frontend'] = $renderingOptions['frontend'];
    }

    if (!empty($publicRenderingOptions)) {
        $result['form']['renderingOptions'] = $publicRenderingOptions;
    }
}

(Currently working around this by hooking into a custom FormDecorator to manually extract and expose these options, but native support for renderingOptions in the extension is needed).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions