HeadersBlog.png
logo Axopen

18+

années
d'expérience

60+

experts
techniques

150K

écoutes de notre podcast

Symfony UX : Révolutionnez facilement votre front-end !

Fatigué de jongler entre Node.jsServeur JavaScript, Webpack et un front-end JavaScriptLangage de scripting orienté objet lourd pendant que vous développez en PHPLangage de programmation s’exécutant côté serveur et permettant la création dynamique de pages web ou d'APIs. ? SymfonyFramework PHP permettant de développer des applications web. UXL'UX signifie "user experience" et définit l'ensemble des éléments permettant l'utilisation du site web de façon optimale. est la solution qui rapproche votre back-end Symfony de votre front-end moderne, sans sacrifier votre productivité ni votre confort avec Twig. Dans cet article, nous allons explorer Symfony UX étape par étape, avec des exemples concrets et directement applicables dans vos projets.

PXL_20251105_101430188.PORTRAIT.jpg
Baptiste LEGAT
Mis à jour le 19 Nov 2025

Voici notre feuille de route :

  • AssetMapper : simplifiez vos assets sans build
  • Symfony UX Turbo : la vitesse d'une SPA sans JavaScript complexe
  • Symfony Stimulus : quand le HTML pilote le JavaScript pour l'interactivité
  • Twig Components : créer des UI réutilisables
  • Conclusion et conseils pratiques

AssetMapper : simplifiez vos assets sans build

Introduit dans SymfonyFramework PHP permettant de développer des applications web. 6.3, AssetMapper transforme la façon dont vous gérez vos assets. Grâce aux Import Maps, il permet de charger vos modules ES directement dans le navigateur, sans étape de build, et souvent sans Node.js.

Note : pour des projets utilisant Sass, TypeScriptLangage de programmation basé sur JavaScript. , Vue/ReactReact est un framework de développement JavaScript populaire. ou ciblant de très anciens navigateurs, un build traditionnel peut rester nécessaire.

Installation recommandée

composer require symfony/asset-mapper symfony/asset
# si vous utilisez Stimulus
composer require symfony/stimulus-bundle

Intégration dans Twig

{% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %}
{% endblock %}

Gérer les dépendances via importmap

php bin/console importmap:require bootstrap
php bin/console importmap:update
php bin/console importmap:outdated

Cette approche simplifie la maintenance et réduit la complexité de votre front-end Symfony.

Symfony UX Turbo : la vitesse d'une SPA sans JavaScript complexe

Symfony Turbo (basé sur Hotwire) permet d'obtenir la vitesse d'une SPA sans écrire une ligne de JavaScriptLangage de scripting orienté objet.

La philosophie : le serveur reste la source de vérité et envoie du HTML, pas du JSON.

Les piliers de Turbo :

  • Turbo Drive : intercepte automatiquement tous les clics et formulaires, effectue la requête en AJAX, et remplace le <body> de la page. C'est invisible et instantané.
  • Turbo Frames : permet de définir des blocs de page indépendants (<turbo-frame>). Une action dans un frame ne rafraîchira que ce frame.
  • Turbo Streams : permet au serveur de pousser des mises à jour HTML au client (via WebSocket, avec Symfony Mercure).

Un formulaire dynamique avec Turbo Frames

Cas d'usage : une section de commentaires qui se met à jour sans recharger la page.

Étape 1 : Le template Twig (l'isolation)

Encapsulez la liste et le formulaire dans un seul <turbo-frame>.

{# templates/article/show.html.twig #}
...
<turbo-frame id="comments-section">
    <h3>Commentaires ({{ article.comments|length }})</h3>
    
    <div id="comment-list">
        {% for comment in article.comments %}
            <p><b>{{ comment.author }}</b> : {{ comment.content }}</p>
        {% endfor %}
    </div>

    {# Le formulaire est DANS le même frame #}
    {{ form_start(comment_form) }}
   ...
    <button type="submit">Envoyer</button>
    {{ form_end(comment_form) }}
</turbo-frame>

Étape 2 : le contrôleur PHP (standard)

Votre contrôleur reste un contrôleur Symfony standard, sans aucune modification.

// src/Controller/ArticleController.php
...
class ArticleController extends AbstractController
{
    public function show(Article $article, Request $request, EntityManagerInterface $em): Response
    {
        //... (création du formulaire)
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            //... (sauvegarde en BDD)
            $this->addFlash('success', 'Merci pour votre commentaire!');

            // Important : on redirige vers la MÊME page
            return $this->redirectToRoute('app_article_show', ['id' => $article->getId()]);
        }

        return $this->render('article/show.html.twig', [
            'article' => $article,
            'comment_form' => $form,
        ]);
    }
}

La magie : Turbo intercepte la soumission. Il suit la redirection en arrière-plan, récupère la nouvelle page complète, mais n'extrait que le bloc <turbo-frame id="comments-section"> de la réponse pour remplacer l'ancien. Le résultat est une mise à jour instantanée, sans rechargement de page. Les erreurs de validation sont gérées de la même manière.

Pour les streams en temps réel, configurez Mercure ou un hub WebSocket.

Symfony Stimulus : quand le HTML pilote le JavaScript pour l'interactivité

Pour l'interactivité purement client-side (ex: afficher/cacher un élément), on utilise Stimulus, le "meilleur ami" de Turbo.

Sa philosophie est l'inverse de React : le HTML (écrit en Twig) pilote le JavaScript.

Installation

composer require symfony/stimulus-bundle

Les 3 concepts de Stimulus

  • Le Contrôleur (**data-controller**) : attache un fichier JS à un élément HTML. data-controller="hello" se lie à hello_controller.js. -Les Actions (**data-action**) : déclenche une méthode JS depuis un événement. data-action="click->hello#greet" appelle la méthode greet() du contrôleur hello au clic.
  • Les Cibles (**data-target**) : permet au contrôleur JS de "trouver" des éléments. data-hello-target="output".

Un "Toggle" de formulaire réutilisable

Étape 1 : Le Twig (HTML-centric)

<div data-controller="toggle">
    <div class="form-check">
        {# L'action : sur "change", appelle la méthode "toggleField" #}
        <input class="form-check-input" 
               type="checkbox" 
               data-action="change->toggle#toggleField"
               data-toggle-target="checkbox"
        >
        <label>J'ai un code promo</label>
    </div>
    
    {# La cible : ce champ sera affiché/caché. #}
    <div data-toggle-target="field" class="d-none mt-2">
        <label>Code Promo</label>
        <input type="text" class="form-control" />
    </div>
</div>

Étape 2 : Le contrôleur Stimulus (générique)

Créez le fichier assets/controllers/toggle_controller.js :

import { Controller } from '@hotwired/stimulus';

// se connecte à data-controller="toggle"
export default class extends Controller {
    
    // Définit les cibles
    static targets = ["checkbox", "field"];

    // Méthode appelée par data-action
    toggleField() {
        if (this.checkboxTarget.checked) {
            this.fieldTarget.classList.remove('d-none');
        } else {
            this.fieldTarget.classList.add('d-none');
        }
    }
}

Remarque : assurez-vous que Stimulus est correctement référencé dans votre importmap si vous utilisez AssetMapper.

Ce contrôleur est 100% générique. Vous pouvez le réutiliser sur tout votre site.

Twig Components : créer des UI réutilisables

Pour une UIL'UI signifie "user interface", et se compose de tous les éléments graphique d'une interface utilisateur. structurée (Alertes, Modales, Cartes), on utilise [symfony/ux-twig-component](https://ux.symfony.com/twig-component). Il apporte le "Component-Driven Development" à Twig.

Chaque composant est un couple :

  • Une classe PHP (src/Twig/Components/) pour la logique et les "props".
  • Un template Twig (templates/components/) pour le HTML.

Créer un composant "Alert"

Étape 1 : Installation

composer require symfony/ux-twig-component

Étape 2 : La classe PHP

Créez src/Twig/Components/Alert.php :

// src/Twig/Components/Alert.php
namespace App\Twig\Components;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

class Alert
{
    // Prop requis
    public string $message;
    // Prop optionnel
    public string $type = 'success';

    // Logique calculée, accessible via {{ this.icon }}
    public function getIcon(): string
    {
        return match ($this.type) {
            'danger' => 'bi:exclamation-circle-fill',
            'warning' => 'bi:exclamation-triangle-fill',
            default => 'bi:check-circle-fill',
        };
    }
}

Étape 3 : Le template Twig (le rendu)

Créez templates/components/Alert.html.twig :

{# templates/components/Alert.html.twig #}
<div class="alert alert-{{ type }} d-flex align-items-center" role="alert">
    {# On appelle la méthode : {{ this.icon }} #}
    <twig:ux:icon name="{{ this.icon }}" class="me-2" />
    <div>
        {# On affiche la prop : {{ message }} #}
        {{ message }}
    </div>
</div>

Étape 4 : L'Appel (la consommation)

Utilisez le dans n'importe quel template Twig :

{# Affiche une alerte de succès (type par défaut) #}
<twig:Alert message="Votre profil a été mis à jour!" />

{# Affiche une alerte d'erreur #}
<twig:Alert type="danger" message="Erreur : Le formulaire est invalide." />

Symfony UX, votre allié pour un front-end moderne !

Symfony UXL'UX signifie "user experience" et définit l'ensemble des éléments permettant l'utilisation du site web de façon optimale. permet de créer des applications modernes et interactives sans complexité excessive, tout en restant dans l'écosystème Symfony/Twig.

Points clés à retenir

  • Productivité accrue : moins de code, tout en PHP/Twig.
  • Maintenance simplifiée : fini la double pile technique front/back.
  • Performance et expérience utilisateur : HTML pré-rendu, interactivité ciblée.
  • Flexibilité : AssetMapper pour les projets simples, Encore/Vite pour les projets lourds.

Envie de passer au niveau supérieur avec Symfony UX ? Commencez à intégrer AssetMapper, Turbo, Stimulus et Twig Components dès aujourd'hui et redonnez du rythme à votre développement Symfony !