Theming Symfony Forms with Twitter Bootstrap

Creating a Layout Template

The first thing we'll need to do to integrate bootstrap is create a basic layout template that will import the bootstrap css and set up the page markup.

Conflation with Assetic

Assetic is a great utility that comes packages with the Symfony Standard distribution that assists with the rendering of assets. Simply put it gathers your CSS and JavaScript and renders each as a single file. Although on a more complicated level, it can compress, minify, compile SASS, LESS and CoffeeScript.

Block Structure with Bootstrap Scaffolding

Twig blocks define areas of content for sub-templates to extend and expand upon. We can wrap these blocks with Bootstrap scaffolding classes like row, container, span12, span2 etc. These two components together make creating the structural layout solid yet extendable.

//src/Titan/KillerCrudBundle/Resources/views/Contract/base.html.twig <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> {% block style %} {% stylesheets '@TitanKillerCrudBundle/Resources/public/css/bootstrap.css' '@TitanKillerCrudBundle/Resources/public/css/bootstrap-responsive.css' '@TitanKillerCrudBundle/Resources/public/css/killer.css' %} <link rel="stylesheet" href="{{ asset_url }}" /> {% endstylesheets %} {% endblock %} </head> <body> {% block body %} <section class="section"> <div class="container"> <div class="row"> <div class="span3"> <ul class="nav nav-tabs nav-stacked"> <li><a href="{{ path('titan_killercrud_default_index') }}">Home</a></li> </ul> </div> <div class="span9"> <div class="row"> {% block content %}{% endblock %} </div> </div> </div> </div> </section> {% endblock %} {% block script %} {% javascripts '@TitanKillerCrudBundle/Resources/public/js/jquery-1.10.2.js' '@TitanKillerCrudBundle/Resources/public/js/bootstrap.js' %} <script type="text/javascript" src="{{ asset_url }}"></script> {% endjavascripts %} {% endblock %} </body> </html>

Custom Rendering Form Components

By using the form_theme twig function we can apply custom markup to the way a form is rendered. Coupling this with bootstrap makes sense and a great place to start is form_errors

//src/Titan/KillerCrudBundle/Resources/views/Form/bootstrap-override.html.twig {% block form_errors %} {% spaceless %} {% if errors|length > 0 %} <ul class="alert alert-error"> {% for error in errors %} <li>{{ error.message }}</li> {% endfor %} </ul> {% endif %} {% endspaceless %} {% endblock form_errors %}

Another common use is a button, this one is pretty simple and it's arguable whether this is best done by the class, because this is a lot more reusable and by is cleaner by way of keeping the presentation out of the form builder.

//src/Titan/KillerCrudBundle/Resources/views/Form/bootstrap-override.html.twig {% block button_attributes %} {% spaceless %} id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif %} {% set hasClass = false %} {% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}" {% if attrname == "class" %} {% set hasClass = true %} {% endif %} {% endfor %} {% if not hasClass %} class="btn" {% endif %} {% endspaceless %} {% endblock button_attributes %}

Advanced Rendering to Achieve a Horizontal Form

To achieve a more vertically compact yet well styled form you can apply overrides to higher level template methods like form_start and form_row

//src/Titan/KillerCrudBundle/Resources/views/Form/bootstrap-form-horizontal.html.twig {% block form_start %} {% spaceless %} {% set method = method|upper %} {% if method in ["GET", "POST"] %} {% set form_method = method %} {% else %} {% set form_method = "POST" %} {% endif %} <form method="{{ form_method|lower }}" class="form-horizontal" action="{{ action }}"{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %}> {% if form_method != method %} <input type="hidden" name="_method" value="{{ method }}" /> {% endif %} {% endspaceless %} {% endblock form_start %} {% block form_row %} {% spaceless %} <div class="control-group"> {{ form_label(form) }} {{ form_errors(form) }} {{ form_widget(form) }} </div> {% endspaceless %} {% endblock form_row %}

Applying a Form Theme

To apply the custom templates above you must include them in your template through the form_theme function in your twig template.

//src/Titan/KillerCrudBundle/Resources/views/Contract/edit.html.twig {% form_theme edit_form with ['TitanKillerCrudBundle:Form:bootstrap-override.html.twig'] %}

External Resources