Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • SensioLabs Professional services to help you with Symfony
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. How to Work with Form Themes
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud

Table of Contents

  • Form Fragment Naming
  • Template Fragment Inheritance
  • Global Form Theming
    • Twig
    • PHP

How to Work with Form Themes

Edit this page

Warning: You are browsing the documentation for Symfony 3.4, which is no longer maintained.

Read the updated version of this page for Symfony 6.2 (the current stable version).

How to Work with Form Themes

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 by form_row() to render most fields;
  • textarea_widget - used by form_widget() to render a textarea field type;
  • form_errors - used by form_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:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
# app/config/config.yml
twig:
    form_themes:
        - '...'
        - 'form/fields.html.twig'
    # ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:twig="http://symfony.com/schema/dic/twig"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">

    <twig:config>
        <twig:theme>...</twig:theme>
        <twig:theme>form/fields.html.twig</twig:theme>
        <!-- ... -->
    </twig:config>
</container>
1
2
3
4
5
6
7
8
// app/config/config.php
$container->loadFromExtension('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.

Customizing Form Output all in a Single File with Twig

In Twig, you can also customize a form block right inside the template where that customization is needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% extends 'base.html.twig' %}

{# import "_self" as the form theme #}
{% form_theme form _self %}

{# make the form fragment customization #}
{% block form_row %}
    {# custom field row output #}
{% endblock form_row %}

{% block content %}
    {# ... #}

    {{ form_row(form.task) }}
{% endblock %}

The {% form_theme form _self %} tag allows form blocks to be customized directly inside the template that will use those customizations. Use this method to quickly make form output customizations that will only ever be needed in a single template.

Caution

This {% form_theme form _self %} functionality will only work if your template extends another. If your template does not, you must point form_theme to a separate template.

PHP

To automatically include the customized templates from the app/Resources/views/form directory created earlier in all templates, modify your application configuration file:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
# app/config/config.yml
framework:
    templating:
        form:
            resources:
                - 'form'
# ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

    <framework:config>
        <framework:templating>
            <framework:form>
                <framework:resource>form</framework:resource>
            </framework:form>
        </framework:templating>
        <!-- ... -->
    </framework:config>
</container>
1
2
3
4
5
6
7
8
9
10
11
// app/config/config.php
$container->loadFromExtension('framework', [
    'templating' => [
        'form' => [
            'resources' => [
                'form',
            ],
        ],
    ],
    // ...
]);

Any fragments inside the app/Resources/views/form directory are now used globally to define form output.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:
    Become certified from home

    Become certified from home

    Check Code Performance in Dev, Test, Staging & Production

    Check Code Performance in Dev, Test, Staging & Production

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of Leonel Machava, a Symfony contributor

    Thanks Leonel Machava for being a Symfony contributor

    2 commits • 4 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony

    Search by Algolia