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).