How to Work with Form Themes
Warning: You are browsing the documentation for Symfony 3.x, which is no longer maintained.
Read the updated version of this page for Symfony 7.1 (the current stable version).
Every part of how a form is rendered can be customized. You're free to change
how each form "row" renders, change the markup used to render errors, or
even customize how a textarea
tag should be rendered. Nothing is off-limits,
and different customizations can be used in different places.
Symfony uses templates to render each and every part of a form, such as
label
tags, input
tags, error messages and everything else.
In Twig, each form "fragment" is represented by a Twig block. To customize any part of how a form renders, you just need to override the appropriate block.
In PHP, each form "fragment" is rendered via an individual template file. To customize any part of how a form renders, you just need to override the existing template by creating a new one.
To understand how this works, customize the form_row
fragment and
add a class attribute to the div
element that surrounds each row. To
do this, create a new template file that will store the new markup:
1 2 3 4 5 6 7 8 9 10
{# app/Resources/views/form/fields.html.twig #}
{% block form_row %}
{% spaceless %}
<div class="form_row">
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
The form_row
form fragment is used when rendering most fields via the
form_row()
function. To tell the Form component to use your new form_row
fragment defined above, add the following to the top of the template that
renders the form:
1 2 3 4 5 6 7
{# app/Resources/views/default/new.html.twig #}
{% form_theme form 'form/fields.html.twig' %}
{# or if you want to use multiple themes #}
{% form_theme form 'form/fields.html.twig' 'form/fields2.html.twig' %}
{# ... render the form #}
The form_theme
tag (in Twig) "imports" the fragments defined in the given
template and uses them when rendering the form. In other words, when the
form_row()
function is called later in this template, it will use the form_row
block from your custom theme (instead of the default form_row
block
that ships with Symfony).
Your custom theme does not have to override all the blocks. When rendering a block which is not overridden in your custom theme, the theming engine will fall back to the global theme (defined at the bundle level).
If several custom themes are provided, they will be searched in the listed order before falling back to the global theme.
To customize any portion of a form, you just need to override the appropriate fragment. Knowing exactly which block or file to override is the subject of the next section.
For a more extensive discussion, see How to Customize Form Rendering.
Form Fragment Naming
In Symfony, every part of a form that is rendered - HTML form elements, errors, labels, etc. - is defined in a base theme, which is a collection of blocks in Twig and a collection of template files in PHP.
In Twig, every block needed is defined in a single template file (e.g. form_div_layout.html.twig) that lives inside the Twig Bridge. Inside this file, you can see every block needed to render a form and every default field type.
In PHP, the fragments are individual template files. By default, they are located in
the Resources/views/Form
directory of the FrameworkBundle (view on GitHub).
Each fragment name follows the same basic pattern and is broken up into two pieces,
separated by a single underscore character (_
). A few examples are:
form_row
- used byform_row()
to render most fields;textarea_widget
- used byform_widget()
to render atextarea
field type;form_errors
- used byform_errors()
to render errors for a field;
Each fragment follows the same basic pattern: type_part
. The type
portion
corresponds to the field type being rendered (e.g. textarea
, checkbox
,
date
, etc) whereas the part
portion corresponds to what is being
rendered (e.g. label
, widget
, errors
, etc). By default, there
are 4 possible parts of a form that can be rendered:
label |
(e.g. form_label() ) |
renders the field's label |
widget |
(e.g. form_widget() ) |
renders the field's HTML representation |
errors |
(e.g. form_errors() ) |
renders the field's errors |
row |
(e.g. form_row() ) |
renders the field's entire row (label, widget & errors) |
Note
There are actually 2 other parts - rows
and rest
-
but you should rarely if ever need to worry about overriding them.
By knowing the field type (e.g. textarea
) and which part you want to
customize (e.g. widget
), you can construct the fragment name that needs
to be overridden (e.g. textarea_widget
).
Template Fragment Inheritance
In some cases, the fragment you want to customize will appear to be missing.
For example, there is no textarea_errors
fragment in the default themes
provided with Symfony. So how are the errors for a textarea
field rendered?
The answer is: via the form_errors
fragment. When Symfony renders the errors
for a textarea
type, it looks first for a textarea_errors
fragment before
falling back to the form_errors
fragment. Each field type has a parent
type (the parent type of textarea
is text
, its parent is form
),
and Symfony uses the fragment for the parent type if the base fragment doesn't
exist.
So, to override the errors for only textarea
fields, copy the
form_errors
fragment, rename it to textarea_errors
and customize it. To
override the default error rendering for all fields, copy and customize the
form_errors
fragment directly.
Tip
The "parent" type of each field type is available in the form type reference for each field type.
Global Form Theming
In the above example, you used the form_theme
helper (in Twig) to "import"
the custom form fragments into just that form. You can also tell Symfony
to import form customizations across your entire project.
Twig
To automatically include the customized blocks from the fields.html.twig
template created earlier in all templates, modify your application configuration
file:
1 2 3 4 5 6
# app/config/config.yml
twig:
form_themes:
- '...'
- 'form/fields.html.twig'
# ...
Note
Add your custom theme at the end of the form_themes
list because each
theme overrides all the previous themes.
Any blocks inside the fields.html.twig
template are now used globally
to define form output.
PHP
To automatically include the customized templates from the app/Resources/views/form
directory created earlier in all templates, modify your application configuration
file:
1 2 3 4 5 6 7
# app/config/config.yml
framework:
templating:
form:
resources:
- 'form'
# ...
Any fragments inside the app/Resources/views/form
directory are now used
globally to define form output.