Skip to content

Introduction

The TYPO3 Form Framework configures the available fields and their properties with YAML. This applies to the form fields in the frontend, but also the Form Editor in the TYPO3 backend.

If the existing form properties are no longer sufficient, we can easily add our own. I will demonstrate this by adding a new select field within the Form Editor, which we will use to render an additional CSS class to design the form in the frontend.

Adding properties in YAML manually

Basically, we can add new properties in the YAML file by hand:

identifier: myContactForm
label: 'Contact us'
type: Form
prototypeName: standard
renderingOptions:
  submitButtonLabel: Submit
  # Added manually:
  myCustomOption: custom-value
renderables:
  -
    renderingOptions:
      previousButtonLabel: 'Previous step'
      nextButtonLabel: 'Next step'
    identifier: page-1
    label: 'Contact Form'
    type: Page
    renderables:
      -
        defaultValue: ''
        identifier: subject
        label: Subject
        type: Text
        properties:
          # Added manually:
          myCustomProperty: 'custom property'

Thankfully, these manually inserted properties are preserved when we subsequently edit the form using the Form Editor in the TYPO3 backend.

These properties are immediately available in the Fluid templates! In the case of our two examples above: {form.renderingOptions.myCustomOption} in the Form.html template; {element.properties.myCustomProperty} in the Partial Field.html or in the Partial of the respective element type, here: Text.html.

Note: The first level of each form element is limited to certain properties. New properties can be added below renderingOptions or properties. If this is disregarded, you will get an exception:
The options "example" were not allowed (allowed were: "label, defaultValue, properties, renderingOptions, validators, formEditor, variants").

If the properties are frequently used, it certainly is convenient for the editor (or integrator) to be able to maintain them directly in the backend.

Our objective: A new select field for the CSS class

In the following, we will configure the field shown in the screenshot(s).

The selected option should render a CSS class in the frontend. In our example, we'll extend the form template with a surrounding div element. The second class will then be set with the value of our select field:

<div class="form  form--subscription">

You can use this classes afterwards to style a form differently.

This tutorial describes one of three solutions to realize individual form styling. See a comparison of these approaches with advantages/disadvantages and applicable use cases.

Adding the field to the Form Editor

The graphical user interface of the Form Editor can be extended through the Form Configuration.

As a reminder, the Form Configuration contains the general settings of the Form Framework. This includes the available form elements and finishers or the sources for language files and templates.
In TYPO3 v10 the configuration of the Form Framework has been neatly split into Partials, which makes it much easier to read. You can find them in the TYPO3 core under typo3/sysext/form/configuration/Yaml/.

If you have already created your custom Form Configuration, you only need the following additions. If not, I explain the preliminary work here.

Resources/Private/Forms/Frontend/Templates/Form.html

In the Form.html template, we only add the div wrapper with our desired classes. The if condition checks whether a value is given: in our example, the value will be empty for the common contact form (but this is not a prerequisite). This will render the second class only for special forms.

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" xmlns:formvh="http://typo3.org/ns/TYPO3/CMS/Form/ViewHelpers" data-namespace-typo3-fluid="true">
<div class="form {f:if(condition: form.renderingOptions.formStyleClass, then: ' form--{form.renderingOptions.formStyleClass}')}">
    <formvh:renderRenderable renderable="{form}">
            <formvh:form
                    object="{form}"
                    action="{form.renderingOptions.controllerAction}"
                    method="{form.renderingOptions.httpMethod}"
                    id="{form.identifier}"
                    section="{form.identifier}"
                    enctype="{form.renderingOptions.httpEnctype}"
                    addQueryString="{form.renderingOptions.addQueryString}"
                    argumentsToBeExcludedFromQueryString="{form.renderingOptions.argumentsToBeExcludedFromQueryString}"
                    additionalParams="{form.renderingOptions.additionalParams}"
                    additionalAttributes="{formvh:translateElementProperty(element: form, property: 'fluidAdditionalAttributes')}"
            >
                <f:render partial="{form.currentPage.templateName}" arguments="{page: form.currentPage}" />
                <div class="actions">
                    <f:render partial="Form/Navigation" arguments="{form: form}" />
                </div>
            </formvh:form>
    </formvh:renderRenderable>
</div>
</html>

YAML configuration

TYPO3:
  CMS:
    Form:
      prototypes:
        standard:
          formElementsDefinition:
            Form:
              renderingOptions:
                templateRootPaths:
                  90: 'EXT:my_sitepackage/Resources/Private/Forms/Frontend/Templates/'
              formEditor:
                editors:
                  500:
                    identifier: formStyleClass
                    templateName: Inspector-SingleSelectEditor
                    label: 'Form styling'
                    propertyPath: renderingOptions.formStyleClass
                    selectOptions:
                      10:
                        value: ''
                        label: 'Contact form'
                      20:
                        value: survey
                        label: 'Survey'
                      30:
                        value: subscription
                        label: 'Newsletter subscription'

Explanation of the configuration

templateRootPaths

As we use a customized version of the Form.html template, we need to define the path where it can be found. It will be located in our sitepackage.

formEditor / editors

Below this property, we add the new field with the arbitrary key "500". Which keys are already assigned for existing fields can be found in the backend module "Configuration" under "Form: YAML configuration".

identifier

This is the unique identifier of your new property.

templateName

Here we use one of the existing Inspector components of the Form Framework. The Inspector-SingleSelectEditor will render the new field as a <select> field.

propertyPath

The identifier is assigned to the renderingOptions of the form here.

selectOptions

Here we can define all desired options of the select field. The label will be visible in the form editor and could also be translated via translation key. The value will be stored in the YAML definition of our forms and can be accessed in our Form.html template as a Fluid variable.

Demo

I added this select field to my demo extension "form_examples". It is available on GitHub. For each TYPO3 version, there is a separate, compatible branch.