How to override a checkbox in Symfony's Twig Form template How to override a checkbox in Symfony's Twig Form template symfony symfony

How to override a checkbox in Symfony's Twig Form template


You should disable rendering label for checkboxes. So you need to override block form_label like this:

{% block form_label %}{% if 'checkbox' not in block_prefixes %}  {{ parent() }}{% endif %}{% endblock form_label %}


In order to correct the order of input and label, you can override the form_row block:

{% block form_row %}  {% spaceless %}    {% if 'checkbox' in block_prefixes %}      {{ form_widget(form) }}      {{ form_label(form) }}    {% else %}      {{ form_label(form) }}      {{ form_widget(form) }}    {% endif %}    {{ form_errors(form) }}  {% endspaceless %}{% endblock form_row %}


The same issue was plaguing our project.

A single Entity field of type PHP Array (so ORM stores it in the database record cell as a JSON string, transparently auto decoding and encoding it) is supposed to break down a list of boolean preferences for the user, each rendered as a checkbox.

So in the EntityType.php, inside the

 public function buildForm(FormBuilderInterface $builder, array $options) $builder ->add('prefs','collection', 

Then, in the main twig template, instead of {{ form(form) }} it's iterated by row:

{% for j,child in form %}   <div id="form-child-{{ j }}" title="form-child-{{ j }}; loop={{loop.index}}">        {{ form_row(child) }}    </div>{% endfor %}     

Though that might not be necessary here.

Higher up in that file, I override the rendering of the form with a theme:

 {% form_theme form 'SystemExtMainBundle:Blocks:checkbox.html.twig' %} 

Which contains:

{% block form_row %}        {% if form.vars.block_prefixes.1 == 'checkbox'   %}<div class="col-xs-12 checkbox-margins checkbox-label-padding">    <div class="errors-container">    {{ form_errors(form)}}    </div>       {{ form_widget(form,{'attr': {'class': '  form-checkbox-widget'}}) }}{{ form_label(form) }}</div>        {% elseif form.vars.block_prefixes.1 == 'choice' %}<div class="col-xs-12 top-form-title">                        {{ form_label(form) }}</div><div class="col-xs-12 select-margins">    <div class="errors-container">    {{ form_errors(form)}}    </div>                      {{ form_widget(form,{'attr': {'class': 'select-style form-control'}}) }}</div>        {% elseif form.vars.block_prefixes.1 == 'submit'%}         {{ form_widget(form,{'attr': {'class': 'top-form-button form-control pull-rigth'}}) }}        {% elseif form.vars.block_prefixes.1 == 'text'%}<div class="col-xs-12 top-form-title">                        {{ form_label(form) }}</div><div class="col-xs-12 ">    <div class="errors-container">    {{ form_errors(form)}}    </div>  

{% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control top-form-input')|trim}) %} {{ form_widget(form,{'attr':attr}) }}

</div>{% else %}<div class="col-xs-12 top-form-title ">                         {{ form_label(form) }}</div><div class="col-xs-12 ">    <div class="errors-container">    {{ form_errors(form)}}    </div>                          {{ form_widget(form) }}</div>        {% endif %}{% endblock form_row %}

The essential part was line #7 above: {{ form_widget(form,{'attr': {'class': ' form-checkbox-widget'}}) }}{{ form_label(form) }} for checkboxes, which reverses the widget and label order into what I wanted (putting the interactive checkbox first, before its text label).