Symfony gives you a wide variety of ways to customize how a form is rendered.
In this guide, you'll learn how to customize every possible part of your
form with as little effort as possible whether you use Twig or PHP as your
templating engine.

In both cases, the form label, errors and HTML widget are rendered by using
a set of markup that ships standard with Symfony. For example, both of the
above templates would render:

1
2
3
4
5
6
7

<div><labelfor="form_age">Age</label><ul><li>This field is required</li></ul><inputtype="number"id="form_age"name="form[age]"/></div>

To quickly prototype and test a form, you can render the entire form with
just one line:

Twig

1
2
3
4
5

{# renders all fields #}{{form_widget(form)}}{# renders all fields *and* the form start and end tags #}{{form(form)}}

PHP

1
2
3
4
5

<!--rendersallfields--><?phpecho$view['form']->widget($form)?><!-- renders all fields *and* the form start and end tags --><?phpecho$view['form']->form($form)?>

The remainder of this recipe will explain how every part of the form's markup
can be modified at several different levels. For more information about form
rendering in general, see How to Control the Rendering of a Form.

Symfony uses form fragments - a small piece of a template that renders just
one part of a form - to render each part of a form - field labels, errors,
input text fields, select tags, etc.

The fragments are defined as blocks in Twig and as template files in PHP.

A theme is nothing more than a set of fragments that you want to use when
rendering a form. In other words, if you want to customize one portion of
how a form is rendered, you'll import a theme which contains a customization
of the appropriate form fragments.

Symfony comes with some built-in form themes that define each and every
fragment needed to render every part of a form:

bootstrap_3_horizontal_layout.html.twig, it's similar to the previous theme,
but the CSS classes applied are the ones used to display the forms horizontally
(i.e. the label and the widget in the same row).

When you use the Bootstrap form themes and render the fields manually,
calling form_label() for a checkbox/radio field doesn't show anything.
Due to Bootstrap internals, the label is already shown by form_widget().

In the next section you will learn how to customize a theme by overriding
some or all of its fragments.

For example, when the widget of an integer type field is rendered, an inputnumber field is generated

The point is, the fragments dictate the HTML output of each part of a form. To
customize the form output, you just need to identify and override the correct
fragment. A set of these form fragment customizations is known as a form "theme".
When rendering a form, you can choose which form theme(s) you want to apply.

In Twig a theme is a single template file and the fragments are the blocks defined
in this file.

In PHP a theme is a folder and the fragments are individual template files in
this folder.

Knowing which Block to Customize

In this example, the customized fragment name is integer_widget because
you want to override the HTML widget for all integer field types. If
you need to customize textarea fields, you would customize textarea_widget.

The integer part comes from the class name: IntegerType becomes integer,
based on a standard.

As you can see, the fragment name is a combination of the field type and
which part of the field is being rendered (e.g. widget, label,
errors, row). As such, to customize how errors are rendered for
just input text fields, you should customize the text_errors fragment.

More commonly, however, you'll want to customize how errors are displayed
across all fields. You can do this by customizing the form_errors
fragment. This takes advantage of field type inheritance. Specifically,
since the text type extends from the form type, the Form component
will first look for the type-specific fragment (e.g. text_errors) before
falling back to its parent fragment name if it doesn't exist (e.g. form_errors).

The easiest way to customize the integer_widget block is to customize it
directly in the template that's actually rendering the form.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

{%extends'base.html.twig'%}{%form_themeform_self%}{%blockinteger_widget%}<divclass="integer_widget">{%settype=type|default('number')%}{{block('form_widget_simple')}}</div>{%endblock%}{%blockcontent%}{# ... render the form #}{{form_row(form.age)}}{%endblock%}

By using the special {% form_theme form _self %} tag, Twig looks inside
the same template for any overridden form blocks. Assuming the form.age
field is an integer type field, when its widget is rendered, the customized
integer_widget block will be used.

The disadvantage of this method is that the customized form block can't be
reused when rendering other forms in other templates. In other words, this method
is most useful when making form customizations that are specific to a single
form in your application. If you want to reuse a form customization across
several (or all) forms in your application, read on to the next section.

You can also choose to put the customized integer_widget form block in a
separate template entirely. The code and end-result are the same, but you
can now re-use the form customization across many templates:

Now that you've created the customized form block, you need to tell Symfony
to use it. Inside the template where you're actually rendering your form,
tell Symfony to use the template via the form_theme tag:

1
2
3

{%form_themeform'form/fields.html.twig'%}{{form_widget(form.age)}}

When the form.age widget is rendered, Symfony will use the integer_widget
block from the new template and the input tag will be wrapped in the
div element specified in the customized block.

Now that you've created the customized form template, you need to tell Symfony
to use it. Inside the template where you're actually rendering your form,
tell Symfony to use the theme via the setTheme() helper method:

So far, to override a particular form block, the best method is to copy
the default block from form_div_layout.html.twig, paste it into a different template,
and then customize it. In many cases, you can avoid doing this by referencing
the base block when customizing it.

This is easy to do, but varies slightly depending on if your form block customizations
are in the same template as the form or a separate template.

Now, when the blocks from form_div_layout.html.twig are imported, the
integer_widget block is called base_integer_widget. This means that when
you redefine the integer_widget block, you can reference the default markup
via base_integer_widget:

If you'd like a certain form customization to be global to your application,
you can accomplish this by making the form customizations in an external
template and then importing it inside your application configuration.

So far, you've seen the different ways you can customize the widget output
of all text field types. You can also customize individual fields. For example,
suppose you have two text fields in a product form - name and
description - but you only want to customize one of the fields. This can be
accomplished by customizing a fragment whose name is a combination of the field's
id attribute and which part of the field is being customized. For example, to
customize the name field only:

Here, the _product_name_widget fragment defines the template to use for the
field whose id is product_name (and name is product[name]).

Tip

The product portion of the field is the form name, which may be set
manually or generated automatically based on your form type name (e.g.
ProductType equates to product). If you're not sure what your
form name is, just view the source of your generated form.

If you want to change the product or name portion of the block
name _product_name_widget you can set the block_name option in your
form type:

When using a collection of forms,
the prototype can be overridden with a completely custom prototype by
overriding a block. For example, if your form field is named tasks, you
will be able to change the widget for each task as follows:

So far, this recipe has shown you several different ways to customize a single
piece of how a form is rendered. The key is to customize a specific fragment that
corresponds to the portion of the form you want to control (see
naming form blocks).

In the next sections, you'll see how you can make several common form customizations.
To apply these customizations, use one of the methods described in the
Form Theming section.

The Form component only handles how the validation errors are rendered,
and not the actual validation error messages. The error messages themselves
are determined by the validation constraints you apply to your objects.
For more information, see the article on validation.

There are many different ways to customize how errors are rendered when a
form is submitted with errors. The error messages for a field are rendered
when you use the form_errors() helper:

Twig

1

{{form_errors(form.age)}}

PHP

1

<?phpecho$view['form']->errors($form['age']);?>

By default, the errors are rendered inside an unordered list:

1
2
3

<ul><li>This field is required</li></ul>

To override how errors are rendered for all fields, simply copy, paste
and customize the form_errors fragment.

You can also customize the error output for just one specific field type.
To customize only the markup used for these errors, follow the same directions
as above but put the contents in a relative _errors block (or file in case
of PHP templates). For example: text_errors (or text_errors.html.php).

Certain errors that are more global to your form (i.e. not specific to just one
field) are rendered separately, usually at the top of your form:

Twig

1

{{form_errors(form)}}

PHP

1

<?phpecho$view['form']->render($form);?>

To customize only the markup used for these errors, follow the same directions
as above, but now check if the compound variable is set to true. If it
is true, it means that what's being currently rendered is a collection of
fields (e.g. a whole form), and not just an individual field.

Twig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

{%form_themeform_self%}{# form_errors.html.twig #}{%blockform_errors%}{%spaceless%}{%iferrors|length>0%}{%ifcompound%}<ul>{%forerrorinerrors%}<li>{{error.message}}</li>{%endfor%}</ul>{%else%}{# ... display the errors for a single field #}{%endif%}{%endif%}{%endspaceless%}{%endblockform_errors%}

PHP

1
2
3
4
5
6
7
8
9
10
11
12

<!-- form_errors.html.php --><?phpif($errors):?><?phpif($compound):?><ul><?phpforeach($errorsas$error):?><li><?phpecho$error->getMessage()?></li><?phpendforeach?></ul><?phpelse:?><!-- ... render the errors for a single field --><?phpendif?><?phpendif?>

When you can manage it, the easiest way to render a form field is via the
form_row() function, which renders the label, errors and HTML widget of
a field. To customize the markup used for rendering all form field rows,
override the form_row fragment. For example, suppose you want to add a
class to the div element around each row:

If you want to denote all of your required fields with a required asterisk (*),
you can do this by customizing the form_label fragment.

In Twig, if you're making the form customization inside the same template as your
form, modify the use tag and add the following:

1
2
3
4
5
6
7
8
9

{%use'form_div_layout.html.twig'withform_labelasbase_form_label%}{%blockform_label%}{{block('base_form_label')}}{%ifrequired%}<spanclass="required"title="This field is required">*</span>{%endif%}{%endblock%}

In Twig, if you're making the form customization inside a separate template, use
the following:

1
2
3
4
5
6
7
8
9

{%extends'form_div_layout.html.twig'%}{%blockform_label%}{{parent()}}{%ifrequired%}<spanclass="required"title="This field is required">*</span>{%endif%}{%endblock%}

When using PHP as a templating engine you have to copy the content from the
original template:

Most of the functions available for rendering different parts of a form (e.g.
the form widget, form label, form errors, etc.) also allow you to make certain
customizations directly. Look at the following example:

Twig

1
2

{# render a widget, but add a "foo" class to it #}{{form_widget(form.name,{'attr':{'class':'foo'}})}}