Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Form Template Customizations

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $6.00

Form Theming: Making Forms Pretty(ish)

Where Form Markup comes from

In episode 2, we built a registration form. Cool! Open up the register.html.twig template for that page. Twig’s form_row function renders the label, input widget and any errors for each field. And with a few other Twig functions, we can render each part individually. That’s all old news, way back from episode 2.

But where does the markup actually come from? Why is the row surrounded in a div and the errors in a ul?

The answer lives deep inside Symfony, in a file called form_div_layout.html.twig. Open it up in your editor.


The location of this file is deep inside Symfony in the vendor directory:


This odd little file holds a lot of blocks and each renders a different part of the form. There’s a block for input fields, labels, errors, and everything else. Every piece of markup for a form is somewhere in here.

Customizing form_row

Find the form_row block. I know it’s shocking, but this is what’s used when we call form_row.

Let’s change it! You should be reminding me that we can’t just modify this file. So, let’s go with your idea and copy this block and create a new form_theme.html.twig file inside app/Resources/views. Copy in the block and add your favorite tag to it, just to see if it’s working:

{# app/Resources/views/form_theme.html.twig #}

{% block form_row %}
    <marquee>It looks like it's working</marquee>
        {{ form_label(form) }}
        {{ form_errors(form) }}
        {{ form_widget(form) }}
{% endblock form_row %}

To tell Symfony about this, go to config.yml and find the twig key. Add form and resources keys and then the name of this template. Since it lives in app/Resources, we use the double-colon syntax, just like when we reference our base template:

# app/config/config.yml
# ...

    # ...
            - "::form_theme.html.twig"

Refresh! For some reason my Marquee takes its time, but there it is! Now, we can override any of the blocks from Symfony’s core form_div_layout.html.twig file.

Twitter Bootstrap Form Theming

Let’s do something useful. A few bundles exist that can help you style your forms for Twitter Bootstrap. Just go to KnpBundles.com and look for them.

To learn a few things, we’ll do some of this by hand. Find the Bootstrap Form Docs.

Every field should have a form-group div around it. As cool as it is, let’s take out the marquee and give the div this class:

{# app/Resources/views/form_theme.html.twig #}

{% block form_row %}
    <div class="form-group">
        {{ form_label(form) }}
        {{ form_errors(form) }}
        {{ form_widget(form) }}
{% endblock form_row %}

Refresh! It’s minor, but we’ve got a little extra margin now. Let’s keep going.

Leave a comment!

Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=5.3.3",
        "symfony/symfony": "~2.4", // v2.4.2
        "doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
        "doctrine/doctrine-bundle": "~1.2", // v1.2.0
        "twig/extensions": "~1.0", // v1.0.1
        "symfony/assetic-bundle": "~2.3", // v2.3.0
        "symfony/swiftmailer-bundle": "~2.3", // v2.3.5
        "symfony/monolog-bundle": "~2.4", // v2.5.0
        "sensio/distribution-bundle": "~2.3", // v2.3.4
        "sensio/framework-extra-bundle": "~3.0", // v3.0.0
        "sensio/generator-bundle": "~2.3", // v2.3.4
        "incenteev/composer-parameter-handler": "~2.0", // v2.1.0
        "doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
        "ircmaxell/password-compat": "~1.0.3", // 1.0.3
        "phpunit/phpunit": "~4.1", // 4.1.0
        "stof/doctrine-extensions-bundle": "~1.1.0" // v1.1.0