Yonel Ceruto
Contributed by Yonel Ceruto in #29680

Consider a Symfony application that contains a custom form field for a color picker that requires some JavaScript code to work. Although Symfony provides multiple options to customize how forms are rendered, the current best solution for simple use cases like this is not simple enough.

In order to make the form field truly reusable, its block name in the form theme must be immutable. However, by default Symfony prefixes the block name with the parent block prefix (e.g. _product_color_widget, _user_color_widget, etc. instead of color_widget)

The solution to this problem is simple but cumbersome:

Step 1. Create a new form type for the custom color widget (the class is almost empty because in this case there's no need to define any option or add any logic):

1
2
3
4
5
6
7
class ColorPickerType extends AbstractType
{
    public function getParent(): string
    {
        return TextType::class;
    }
}

Step 2. Update your forms to use this custom form type:

1
2
// ...
$builder->add('color', ColorPickerType::class);

The block_prefixes option generated by Symfony for this type will be form, text, color_picker and _<parent_form_name>_color. Thanks to the unchanging color_picker prefix, you can now define a custom template for all the color pickers of the app using the same block name.

Step 3. Use the block prefix to customize the form field:

1
2
3
4
5
{# templates/form/fields.html.twig #}
{% block color_picker_widget %}
    {{ form_widget(form, {'attr': {'v-model': 'color', '@focus': 'open'}}) }}
    {# ... more custom code here ... #}
{% endblock %}

In Symfony 4.3 all this still works, but we've streamlined this use case. Thanks to the new block_prefix option, you can add any custom prefix to the list of prefixes generated by Symfony for each form field.

Following the same example as above, there's no need to create the ColorPickerType class. You just need to follow these steps:

Step 1. Define a custom block prefix for the color form field:

1
2
// ...
$builder->add('color', null, ['block_prefix' => 'color_picker']);

Step 2. Use that custom block prefix in the form theme template:

1
2
3
4
{# templates/form/fields.html.twig #}
{% block color_picker_widget %}
    {# ... #}
{% endblock %}
Published in #Living on the edge