Image mise en avant pour l'article

Symfony UX : à la rencontre des Twig Components

23 juin 2025
PHP - Symfony
Les frameworks front-end ont changé la manière de structurer nos interfaces grâce aux composants. Mais qu’en est-il côté back-end avec Symfony et Twig ? Le framework Symfony propose lui aussi une approche modulaire du rendu. Je vous propose d’explorer ensemble une première pièce du puzzle avec les Twig Components.


Les frameworks front-end, comme React, Angular ou Vue, ont apporté une manière de développer une page Web différente de ce qu’on a pu faire jusqu’à présent : le découpage en composant. Cette approche est très pratique car elle permet de réutiliser des composants d’une page à une autre, et favorise également l’isolation du code. Chaque composant reste donc dans son propre scope, bien qu’un transfert de données soit possible… du parent vers l’enfant et inversement.

Mais alors comment concevoir une page avec le framework Symfony (avec le moteur de template par défaut Twig) ? Dans notre boite à outils, le tag include, très simple d’utilisation, permet déjà un bon découpage de notre page. Le tag embed, quant à lui, fonctionne de manière comparable, mais donne en plus la possibilité de surcharger certaines parties du contenu.

Un peu léger, non ? Bien que ça suffise amplement, dès qu’on se met dans le mindset d’un framework front-end, on se retrouve vite au pied du mur. C’est là qu’entrent en action les Twig Component.

L’initiative Symfony UX est née en 2020. Ce projet facilite l’intégration de packages rendant votre application plus dynamique, plus smooth… et surtout, sans prise de tête avec JavaScript. On limite ainsi l’usage du JS, et dans certains cas, on peut même s’en passer totalement.

Les Twig Components, même s’ils n’embarquent pas de JavaScript (contrairement aux Live Components, mais on en reparlera dans un prochain article 😉), font partie de ces packages proposés par Symfony UX.

Un développeur Symfony consulte le code d'une application sur plusieurs écrans

Exemple d’un Twig Component simple avec Symfony UX

Un Twig Component se compose de deux fichiers : une classe PHP et un template Twig. Dans la classe PHP, on pourra inclure de la validation de données, injecter des services ou des managers. Dans le template Twig, sans surprise, on retrouve le contenu que l’on souhaite rendre réutilisable. Voyons maintenant une mise en application simple.

La classe PHP utilise un attribut « AsTwigComponent » qui permet de la déclarer comme composant. Le paramètre template est facultatif, mais utile si l’on souhaite nommer le template différemment. Par défaut, le framework Symfony s’attend à trouver un template portant le même nom que la classe dans le dossiers components. Ce dernier est modifiable dans la configuration twig_component.yaml. Définir explicitement le nom du template permet également d’éviter les confusions si plusieurs fichiers portent le même nom.

On déclare ensuite nos propriétés (ou props), qui seront directement accessible dans le template.

Code PHP montrant la déclaration d'un composant Twig nommé Card avec trois propriétés : title, image et description

La partie Twig, quant à elle, présente deux particularités :

  • Une variable attributes, qui permet de transmettre des attributs supplémentaires lors de l’appel du composant (comme des data ou aria attributs).
  • De la même manière qu’on peut passer des props, et également lui injecter du HTML. Pour se faire, il s’agit d’utiliser la syntaxe `twig:block`(Pour les connaisseurs de Vue, c’est l’équivalent des slots).

Template Twig affichant une carte avec condition d’affichage d’image, un titre, une description et un bloc action personnalisable

Et maintenant, l’appel du composant :

Appel d’un composant Twig Card avec des props dynamiques et un bloc nommé action contenant un bouton Adopt me

Comme vous le voyez, pour appeler notre composant il suffit de démarrer notre tag par `twig:`, suivi du nom du composant. Notre tag peut également s’auto-fermer si on n’utilise pas de block. Ici comme il en a un, nous ajoutons un bouton à l’intérieur. Et vous remarquez ? C’est également un composant !

Note - Il existe deux syntaxes possibles : HTML et Twig. Je vous conseille d’utiliser la première, plus lisible, et surtout compatible avec l’auto-complétions de l’IDE.

Alors, je vous le concède, la classe PHP, ici, hormis déclarer des props, ne sert strictement à rien 😅. Modifions donc notre composant pour créer un composant anonyme.

  1. On supprime complètement la classe PHP.
  2. On ajoute une ligne dans notre template Twig pour déclarer les props dont nous avons besoin.

Extrait de composant Twig anonyme avec déclaration de props et structure HTML contenant une div stylisée

Puisque que notre template est dans le dossier `/templates/components`, et qu’il se nomme `Card.html.twig`, il n’est pas nécessaire de modifier le(s) appel(s) de notre composant.

Exemple d’un Twig Component plus complexe avec Symfony

Notre précédent composant ne nécessitait pas de classe PHP puisqu’on ne faisait que déclarer des props. Il était donc plus judicieux d’en faire un composant anonyme. Voyons maintenant comment la classe PHP peut réellement nous servir.

Dans cet exemple, notre composant devra faire deux choses :

  • Valider les données reçues : est-ce que le type est pris en compte par notre composant ?
  • Récupérer de la données (via une API ou base de données).

Validation des données passé au composant

Avant que le composant soit instancié, on peut vérifier les données passées grâce à l’attribut `#[PreMount]`. Dans notre cas, deux props sont attendues : animalType et animals. On peut donc effectuer des vérifications sur l’une, l’autre… ou les deux.

Concrètement, on va :

  • définir une valeur par défaut (cat) pour animalType ;
  • restreindre les valeurs autorisées à cat et dog ;
  • ignorer les autres props non déclarées pour ne pas bloquer l’exécution (ligne 5) ;
  • fusionner les données validées avec les données reçues (ligne 10).

Ce comportement est assez proche de ce qu’on fait dans la méthode configureOptions() d’un formulaire Symfony.

Code PHP utilisant PreMount pour définir une valeur par défaut et restreindre les valeurs autorisées de la prop animalType dans un composant

Formidable, maintenant que nos données sont validées, on peut passer à la récupération des données.

Récupérer des données après validation

Pour récupérer nos données, je vous propose de le faire de la façon la plus simple possible. On va injecter un service dans notre composant, puis utiliser l’attribut PostMount.

Cet attribut est un autre hook disponible qui va nous permettre de réaliser des actions supplémentaires une fois le composant instancié.

Comme nos données d’entrées ont été vérifiées en amont via PreMount, on peut hydrater la props animals.

Exemple de méthode postMount avec l’attribut PostMount pour appeler dynamiquement getCatsList ou getDogsList selon le type d’animal

Voici la version complète de notre composant Animals :

Classe PHP Animals déclarée comme Twig Component, avec validation des props via PreMount et récupération des données selon animalType via PostMount

Et son template associé :

Template Twig affichant une liste d’animaux sous forme de composants Card avec bouton personnalisé dans une grille responsive

Je récapitule…

La classe Animals vérifie le type passé en entrée, puis récupère les données associées.
Le template Twig Animals boucle sur ces données et affiche une série de composants Card.
Chaque Card appelle à son tour un composant Button.

En résumé : trois composants réutilisables, chacun autonome. Et lorsqu’on assemble tout ça, voici le rendu obtenu en image. Pas mal, non ? Et surtout : c’est français. 😊

Interface affichant trois cartes avec photo de chats nommés Hector, Jasmin et Booba, une courte description et un bouton Adopt me pour chacun

Class Variance Authority, un Twig Component encore plus réutilisable

Pour pousser encore un peu plus loin la logique de réusabilité, les Twig Components permettent aussi d’exploiter le concept de Class Variance Authority (CVA). Issu du monde du front-end, ce principe permet de définir plusieurs variantes d’un même composant à partir de quelques règles simples.

Dans notre exemple, nous avons un bouton capable d’adopter différentes tailles et couleurs. Et comme nous avons également une props has_link, notre bouton pourra être un lien (<a>) ayant l’apparence d’un bouton.

Comme pour le composant Card, Button ne nécessite pas de classe PHP. On y déclare nos props en premier lieu puis nous créons un objet CVA (L8) avant d’être servi dans notre tag :

Extrait de composant Twig définissant un bouton personnalisable via html_cva avec des variantes de couleur et taille, et lien conditionnel

Pour créer cet objet CVA, on utilise la fonction Twig html_cva(). Elle prendra en premier paramètre la classe de base qui sera tout le temps présente. Le second paramètre sera un objet pour définir les différentes variantes possibles. Ici, la couleur et la taille.

Ensuite, on va ensuite appliquer les classes CSS en appelant la méthode `apply()` sur notre objet. La méthode nécessite un premier paramètre qui sera un tableau. Dans ce dernier on passe les deux variantes. Le second paramètre correspond aux classes additionnelles que l’on passerait à notre composant (optionnel).

À l'usage, notre composant pourrait aussi servir comme bouton de déconnexion à l’aide des props que l’on a défini dans objet CVA :

Exemple d’appel du composant Twig Button avec props color neutre, size sm et has_link true pour créer un lien de déconnexion

Et voici le rendu de notre exemple :

Interface utilisateur avec un menu déroulant incluant l’e-mail foo@bar.com, un lien Settings et un bouton arrondi violet pour se déconnecter

Pourquoi utiliser CVA dans un Twig Component ? L’intérêt est triple. Déjà on évite de surcharger l’attribut HTML class. De faciliter la maintenance de ce composant, que ce soit en termes de style ou de fonctionnalité. Et surtout, l’IDE permet d’afficher automatiquement les valeurs valides pour chaque prop de votre composant.
On ne parle pas assez de l’expérience développeur, mais elle a aussi son importance.


Pour conclure - À travers ces exemples, on a vu que les Twig Components permettent de créer des composants plus ou moins simples, imbricable, dont les propriétés peuvent faire varier l’apparence.

Qu’ils aient besoin de données ou non, où que vous souhaitiez les afficher, il suffit de les appeler dans un template Twig – aucun effort supplémentaire.

Dans un prochain article, j’irai un peu plus loin avec les Live Components. Ce ne sont ni plus ni moins que des Twig Components couplés à Stimulus. Ce combo rend nos composants dynamiques rendant l’expérience utilisateur plus fluide avec un effet wahoo. Est-ce que nous avons réellement encore besoin de développer des Single Page Application (SPA) ? Symfony UX commence à nous prouver que non.

Crédit photo : Deagreez
Sources :

Image mise en avant pour l'article
Yannick François
Développeur Web - Pôle Framework & DevOps
Quelle technologie choisir pour votre projet digital ?
Drupal, Symfony, WordPress..., nos experts vous conseillent la meilleure solution technique pour votre projet
Contactez-nous !