Skip to content

What's it about?

This tutorial is not about simply overriding the default Form Framework templates in the sitepackage. Instead, I want to describe how to provide different looking forms within the same TYPO3 installation.

Possible tasks:

  1. The styling of the newsletter form should be different from the contact form.
  2. The TYPO3 installation contains the websites of three different subsidiaries, whose forms each require different templates.
  3. Editors should be able to create new forms in the Form Editor; depending on the type of form, different templates or even form fields must be available.

First approach: Select field in the Form Editor

You can add a new select field (dropdown) with styling options in the Form Editor for your editors. The selected styling is then added to the form template as a fluid variable ( in this example: formStyleClass). You can use it to set a CSS class on the form.

<div class="form {f:if(condition: form.renderingOptions.formStyleClass, then: ' form--{form.renderingOptions.formStyleClass}')}">
   <formvh:renderRenderable renderable="{form}">
       <!-- […] -->
   </formvh:renderRenderable>
</div>

Advantages of the select field

  • Can be configured with little effort
  • The styling is freely selectable by editors in the TYPO3 backend
  • Minor styling adjustments where the HTML markup of the form fields does not need to be changed

How do I configure a styling select field?

I have already described this exact case step by step in this tutorial.

Second approach: Separation of frontend configuration per page tree

The configuration of the Form Framework is usually customized in a single YAML file in the site package.

However, if we respect some simple basic rules, the template paths and other frontend-related configurations can be loaded independently per page tree without causing problems in the backend.

Advantages of separation by website

  • Template paths or configured CSS classes in YAML allow you to use different HTML markup in forms.
  • With XLIFF translation files you can also define different form labels per page tree

Disadvantages when separating the YAML configuration

  • You have to ensure that any Backend-related configuration of the Form Framework is maintained in the globally loaded configuration file
  • TYPO3 installations with multiple page trees, each of which should use different form templates or labels (e.g. for subsidiaries with their own corporate design)

How do I separate the frontend configuration from the globally required configuration?

I have not described this case in any of the existing tutorials, so I explain it below. I also created a Proof of Concept as an extension on Github:

EXT:form_configsplit on GitHub

The extension is created only for TYPO3 v12, but you can apply the concept in all TYPO3 versions with the Form Framework.

Globally required form configuration

FormSetup.yaml:

persistenceManager:
  allowedExtensionPaths:
    500: EXT:form_configsplit/Resources/Private/Forms/
  allowSaveToExtensionPaths: true
  allowDeleteFromExtensionPaths: true

TYPO3 must always know where to find forms: for editing in the form editor, for selection in the plugin, and, of course, for output in the frontend.

The other settings for the persistenceManager must be available in the backend as well. Therefore, we will load these settings in the FormSetup.yaml globally in TYPO3.

Possible form configuration per page tree

In the following example configurations, we each define a custom XLIFF translation file and individual template paths. We also set a CSS class for <textarea> elements via YAML.

Our example page trees will be configured for the two companies Laurel Corp. and Hardy Ltd.

FrontendLaurelCorporation.yaml:

prototypes:
  standard:
    formElementsDefinition:
      Form:
        renderingOptions:
          translation:
            translationFiles:
              501: 'EXT:form_configsplit/Resources/Private/Language/locallang_laurel.xlf'
          templateRootPaths:
            501: 'EXT:form_configsplit/Resources/Private/Frontend/Laurel/Templates/'
          partialRootPaths:
            501: 'EXT:form_configsplit/Resources/Private/Frontend/Laurel/Partials/'
          layoutRootPaths:
            501: 'EXT:form_configsplit/Resources/Private/Frontend/Laurel/Layouts/'
      Textarea:
        properties:
          elementClassAttribute: 'textarea--laurel'

FrontendHardyLimited.yaml:

prototypes:
  standard:
    formElementsDefinition:
      Form:
        renderingOptions:
          translation:
            translationFiles:
              502: 'EXT:form_configsplit/Resources/Private/Language/locallang_hardy.xlf'
          templateRootPaths:
            502: 'EXT:form_configsplit/Resources/Private/Frontend/Hardy/Templates/'
          partialRootPaths:
            502: 'EXT:form_configsplit/Resources/Private/Frontend/Hardy/Partials/'
          layoutRootPaths:
            502: 'EXT:form_configsplit/Resources/Private/Frontend/Hardy/Layouts/'
      Textarea:
        properties:
          elementClassAttribute: 'textarea--hardy'

YAML registration

All three YAML configurations must now be registered with TypoScript.

In the first step we load the globally needed configurations into TYPO3.

ext_localconf.php:

ExtensionManagementUtility::addTypoScriptSetup(
    trim('
         module.tx_form.settings.yamlConfigurations {
            500 = EXT:form_configsplit/Configuration/Form/FormSetup.yaml
        }

        plugin.tx_form.settings.yamlConfigurations {
            // Wichtig: hier nur das globale YAML laden!
            500 = EXT:form_configsplit/Configuration/Form/FormSetup.yaml
        }
    ')
);

Next, we create two TypoScript files for the frontend configurations. Here we load the YAML only for plugin.tx_form.

Configuration/TypoScript/Laurel/setup.typoscript:

plugin.tx_form.settings.yamlConfigurations {
    501 = EXT:form_configsplit/Configuration/Form/FrontendLaurelCorporation.yaml
}

Configuration/TypoScript/Hardy/setup.typoscript:

plugin.tx_form.settings.yamlConfigurations {
    502 = EXT:form_configsplit/Configuration/Form/FrontendHardyLimited.yaml
}

We then provide these two TypoScripts as Static Includes in TypoScript records.

Configuration/TCA/Overrides/sys_template.php:

ExtensionManagementUtility::addStaticFile(
    'form_configsplit',
    'Configuration/TypoScript/Laurel/',
    'Form frontend setup: Laurel Corporation'
);

ExtensionManagementUtility::addStaticFile(
    'form_configsplit',
    'Configuration/TypoScript/Hardy/',
    'Form frontend setup: Hardy Limited'
);

That's it! From now on, all forms in the respective page trees should take the defined template paths, translations and properties into account.

Third approach: Custom form prototypes

The TYPO3 Form Framework includes the concept of so-called prototypes. Each form is based on a prototype. Per default, the "standard" prototype is used.
You can configure your own prototypes via YAML and provide them in the Form Editor.

In the backend, you can only assign a prototype when creating a new form, and that's for the following reason: per prototype you can configure which form fields or finishers will be available in the Form Editor.

See also the official documentation on prototypes.

Advantages of user-defined form prototypes

  • Prototypes can inherit their basic properties from the "standard" prototype
  • Configuration of custom template paths, CSS classes and XLIFF language files
  • Configuration of available form fields, finishers etc.

Disadvantages of user-defined form prototypes

  • The prototype of a form can not be changed afterward in the Form Editor of the TYPO3 backend (because the available form fields are based on it)
  • The setup requires a comparatively extensive YAML configuration
  • Complex TYPO3 installations
  • Projects in which editors are allowed to create forms independently

How do I configure a custom form prototype?

I have also already written a dedicated tutorial on this topic and revised it subsequently.

Conclusion

I hope this overview helps you to decide which approach to choose. The solutions are not mutually exclusive. If the TYPO3 project requires it, you could combine two or even all three solutions. Just keep the increasing complexity in mind.