Skip to Content
SymfonyPartie 9 — Formulaires, validation & upload9.4 — Thématiser les formulaires

Chapitre 9.4 — Thématiser les formulaires

Partie 9 : Formulaires — Chapitre 4/5 Version de référence : Symfony 7.4.

⏱️ TL;DR

  • Un form theme contrôle comment les champs sont rendus en HTML (structure, classes CSS). Symfony fournit des thèmes prêts : Bootstrap 5, Tailwind, et le thème par défaut.
  • On active un thème globalement dans config/packages/twig.yaml (form_themes) ou par template ({% form_theme form 'bootstrap_5_layout.html.twig' %}).
  • Pour personnaliser, on surcharge des blocs (ex. form_row, text_widget) dans son propre thème.
  • Les options attr, row_attr, help, label_attr ajustent classes et textes sans thème custom.
  • Pour un dev Next.js : le form theme, c’est votre couche de présentation des champs (comme un design system de composants de formulaire), séparée de la logique du formulaire.

🎯 Objectifs

  • Activer un thème de formulaire (Bootstrap/Tailwind).
  • Ajuster le rendu via les options de champ.
  • Surcharger des blocs pour un rendu sur-mesure.

1. Appliquer un thème global

Le rendu par défaut de Symfony est neutre. Pour un rendu Bootstrap 5 ou Tailwind, on le déclare une fois :

# config/packages/twig.yaml twig: form_themes: - 'bootstrap_5_layout.html.twig' # ou : 'tailwind_2_layout.html.twig'

Désormais, tous les {{ form(form) }} et {{ form_row(...) }} produisent du HTML avec les classes attendues par Bootstrap/Tailwind. Aucun changement dans vos FormType : c’est purement présentationnel.

On peut aussi appliquer un thème localement dans un template :

{% form_theme form 'bootstrap_5_layout.html.twig' %} {{ form(form) }}

2. Ajuster le rendu sans thème custom

Beaucoup de personnalisations passent par les options de champ, sans écrire de thème :

->add('customerEmail', EmailType::class, [ 'label' => 'Email du client', 'help' => 'On y enverra la confirmation.', // texte d'aide 'attr' => ['class' => 'input-lg', 'placeholder' => 'nom@exemple.fr'], // sur le widget 'row_attr' => ['class' => 'form-group-highlight'], // sur la ligne 'label_attr' => ['class' => 'fw-bold'], ])
  • attr : attributs HTML du widget (le <input>).
  • row_attr : attributs de la ligne entière (label + widget + erreurs).
  • label_attr : attributs du label.
  • help : un texte d’aide affiché sous le champ.

3. Surcharger des blocs pour un rendu sur-mesure

Un form theme est un fichier Twig qui définit des blocs nommés par convention (form_row, text_widget, form_errors, checkbox_widget…). Pour personnaliser, on crée son thème qui surcharge les blocs voulus :

{# templates/form/theme.html.twig #} {% use 'bootstrap_5_layout.html.twig' %} {# on part de Bootstrap et on ajuste #} {# personnaliser l'affichage des erreurs #} {% block form_errors %} {% if errors|length > 0 %} <ul class="my-error-list"> {% for error in errors %} <li>⚠️ {{ error.message }}</li> {% endfor %} </ul> {% endif %} {% endblock %}

On l’active comme thème (global ou local). Le {% use %} hérite d’un thème existant et permet de ne redéfinir que les blocs qui changent.

4. Rendu personnalisé d’un champ précis

Pour un champ particulier, on peut aussi tout écrire à la main autour du widget :

{{ form_start(form) }} <div class="my-field"> {{ form_label(form.seats) }} <div class="input-with-icon"> <span class="icon">👥</span> {{ form_widget(form.seats) }} </div> {{ form_errors(form.seats) }} </div> {{ form_rest(form) }} {# rend les champs restants non affichés manuellement (dont le token CSRF !) #} {{ form_end(form) }}

⚠️ Piège : quand vous rendez les champs manuellement un par un, n’oubliez pas form_rest(form) (ou form_end qui l’inclut par défaut) : il rend les champs non encore affichés, dont le token CSRF caché. L’oublier → formulaire invalide (token manquant). Si vous utilisez form_end(form) sans avoir désactivé render_rest, il s’en charge.

5. Cohérence avec AssetMapper/Tailwind

Si vous stylez en Tailwind (chapitre 7.3), utilisez le thème tailwind_2_layout.html.twig (ou le vôtre) et ajoutez vos classes via attr/row_attr. L’ensemble reste rendu serveur, cohérent avec le back-office Twig.

💡 Pour un dev Next.js : pensez au form theme comme à un design system de champs : la logique (le FormType, la validation) est séparée de la présentation (le thème). Changer de thème (Bootstrap → Tailwind) ne touche pas la logique — comme swapper la couche de style d’un composant sans changer sa logique.

✏️ Exercices

Exercice 1. Activez le thème Bootstrap 5 pour tous les formulaires du projet. Où et comment ?

✅ Solution

Dans config/packages/twig.yaml :

twig: form_themes: - 'bootstrap_5_layout.html.twig'

Global à tout le projet, sans toucher aux FormType. (Alternative locale : {% form_theme form 'bootstrap_5_layout.html.twig' %} en tête d’un template.)

Exercice 2. Vous rendez un formulaire champ par champ manuellement et la soumission est toujours invalide (token CSRF manquant). Que faut-il ajouter ?

✅ Solution

form_rest(form) avant form_end (ou s’assurer que form_end(form) rend bien le reste) : il affiche les champs non rendus manuellement, dont le token CSRF caché. Sans lui, le token n’est pas dans le HTML, donc la validation CSRF échoue et le formulaire est invalide.

Exercice 3. Vous voulez ajouter un placeholder et une classe CSS à un champ sans créer de thème. Comment ?

✅ Solution

Via l’option attr du champ dans le FormType : ->add('customerEmail', EmailType::class, ['attr' => ['class' => 'input-lg', 'placeholder' => 'nom@exemple.fr']]). (row_attr pour la ligne, label_attr pour le label.) Pas besoin de thème custom pour de simples ajustements d’attributs.

🧠 Quiz de révision

1. Qu’est-ce qu’un form theme ?

Une couche présentationnelle qui définit comment les champs sont rendus en HTML (structure, classes). Symfony fournit Bootstrap 5, Tailwind, et un thème par défaut.

2. Où active-t-on un thème global ?

Dans config/packages/twig.yaml (twig.form_themes), ou localement avec {% form_theme form '...' %}.

3. Comment ajuster classes/aide sans thème custom ?

Via les options de champ : attr (widget), row_attr (ligne), label_attr (label), help (texte d’aide).

4. Comment personnaliser le rendu des erreurs ?

En surchargeant le bloc form_errors dans un thème custom (souvent avec {% use 'bootstrap_5_layout.html.twig' %} pour n’ajuster que ce bloc).

5. Que rend form_rest(form) et pourquoi est-ce important ?

Les champs non encore rendus manuellement, dont le token CSRF caché. L’oublier rend le formulaire invalide.


Prochain chapitre : 9.5 — Upload de fichiers — champ FileType, VichUploader, stockage Flysystem/S3 et sécurité.