Aller au contenu principal

Live Components : JavaScript, moi non plus

Créez des interfaces réactives en PHP avec les Live Components de Symfony : pas de JavaScript, juste du Twig et des composants dynamiques.
Catégorie

Symfony

Architecture, composants et patterns avancés du framework Symfony.

Lecture
4 min
Niveau
Intermédiaire
oct 15 2025
Partager

C'est le syndrome classique. Vous faites un site Symfony propre, rapide, SEO-friendly. Et là, le client demande : "Ce serait bien si la liste se mettait à jour quand je tape dans la recherche, sans recharger la page."

Le développeur en vous soupire. "Bon, il faut que je crée une API JSON, que j'installe React/Vue, que je configure Webpack/Vite, que je gère le state, que je duplique mes templates Twig en JSX..."

Stop. Vous n'a vez pas besoin d'une usine à gaz pour une fonctionnalité d'interaction. Vous avez besoin des Live Components.

La réactivité sans le "JS Fatigue"

Live Components (symfony/ux-live-component), c'est la magie de la réactivité, mais pilotée par le serveur. Le principe est simple et redoutable :

  1. Le composant s'affiche en HTML (Server Side Rendering).
  2. L'utilisateur tape dans un input (<input data-model="query">).
  3. Au lieu de gérer ça en JS, le composant envoie une requête AJAX légère à Symfony.
  4. Symfony met à jour la propriété PHP $query, ré-exécute le rendu Twig.
  5. Le serveur renvoie le nouveau HTML.
  6. Le composant se met à jour intelligemment (diffing de DOM) sans perdre le focus.

Vous n'avez écrit AUCUNE ligne de JavaScript. Pas d'API. Pas de Serializer. Pas de duplication de logique.

La recherche en temps Réel

Plutôt qu'un exemple théorique, regardez le code réel de mon composant de recherche (src/Twig/Component/Content/Search.php). On est loin du "Hello World".

PHP
#[AsLiveComponent(name: 'Content:Search', template: 'components/Content/Search.html.twig')]
class Search
{
    use DefaultActionTrait; // Gère les actions automatiques

    #[LiveProp(writable: true)]
    #[ExposeInTemplate]
    public string $query = '';

    #[LiveProp(writable: true)]
    #[ExposeInTemplate]
    public ?string $category = null;

    public function __construct(
        // On injecte Meilisearch directement, pas besoin de passer par un Controller !
        private readonly MeilisearchSearchService $meilisearchSearchService,
    ) {}

    #[ExposeInTemplate('searchResults')]
    public function getSearchResults(): array
    {
        // 1. On nettoie l'entrée utilisateur
        $query = $this->normalizedQuery();

        if (\strlen($query) < 3) {
            return [];
        }

        // 2. On interroge le moteur de recherche
        // Cette méthode est rejouée à chaque frappe côté serveur !
        return $this->meilisearchSearchService->search(
            $query,
            limit: 8,
            filters: ['category' => $this->category],
            sort: 'createdAt:desc'
        );
    }
    
    // ... méthode normalizedQuery() pour éviter les injections ...
}

Et le template ? Il est d'une simplicité enfantine.

Twig
<div data-controller="search">
    <!-- Le champ est lié au PHP via data-model="query" -->
    <!-- L'attribut data-loading gère l'UX pendant la requête réseau -->
    <div class="relative">
        <input type="search" data-model="query" placeholder="Rechercher..." />
        
        <!-- Spinner SVG affiché uniquement pendant le chargement -->
        <svg data-loading="removeClass(hidden)" class="hidden animate-spin">...</svg>
    </div>

    <!-- Les résultats s'affichent ici -->
    <div class="results">
        {% for post in this.searchResults %}
            <twig:Content:Post :post="post" />
        {% else %}
            {% if this.hasNoResults %}
                <p>Aucun résultat trouvé.</p>
            {% endif %}
        {% endfor %}
    </div>
</div>

C'est tout. Quand l'utilisateur tape, $query est mis à jour côté serveur via une requête AJAX ultra-légère. getSearchResults() est rappelé, et Live Components renvoie le nouveau HTML de la div résultats. C'est aussi fluide qu'une SPA (Single Page App), mais avec la simplicité developer-experience de PHP.

Quand utiliser Live Components ?

Est-ce que ça remplace React pour faire Google Maps ou Trello ? Non. Pour des applis hautement interactives avec gestion d'état complexe côté client, JS reste roi.

Mais pour 90% des besoins web classiques :

  • Recherche / Filtres dynamiques
  • Pagination sans rechargement
  • Formulaires d'édition inline
  • Paniers d'achat
  • Modales et sidebars

Utiliser React/Vue pour ça en 2026 est de la sur-ingénierie (Over-engineering). Ça alourdit le bundle, complexifie le build, et sépare le front du back inutilement.

Les "super-pouvoirs" cachés

  1. Validation Temps Réel : Vu que c'est PHP qui tourne, vous utilisez vos Assert Symfony (#[Assert\Email]). Le formulaire se valide en live, avec les mêmes règles que votre backend. Sécurité maximale.
  2. Synchronisation URL : Ajoutez url: true à votre propriété (#[LiveProp(url: true)]). L'URL du navigateur se met à jour quand on tape (?query=foo). Le bouton "Précédent" du navigateur marche. Sans effort.

Le mot de la fin

Live Components redonne le pouvoir au développeur Backend. Il permet de créer des expériences utilisateur "Premium" (réactives, fluides) sans payer la "Taxe JavaScript" (complexité, maintenance).

C'est le chaînon manquant qui permet à Symfony de rivaliser avec les frameworks JS modernes sur leur propre terrain : l'interactivité. Essayez-le sur votre prochaine feature "dynamique". Vous ne reviendrez pas en arrière.

Poursuivre la lecture

Sélectionné avec soin pour vous.

PHP

Recommandations de contenu avec Meilisearch

Implémentez un système de recommandation d'articles sur votre blog Symfony en utilisant Meilisearch comme moteur de similarité sémantique.

8 min de lecture
UX

Comment j'ai transformé EasyAdmin en tableur intelligent

Implémentez l'édition inline dans EasyAdmin avec Symfony UX Turbo et Stimulus. Textes, enums, dates, associations : modifiez vos champs sans quitter la liste.

5 min de lecture
PHP

Meilisearch : l'art de la recherche instantanée

Marre du SQL LIKE ? Découvrez comment intégrer Meilisearch à Symfony pour une recherche résiliente, asynchrone et une latence inférieure à 50ms.

5 min de lecture