Aller au contenu principal

Comment tailwind_merge résout les conflits de classes dans Twig.

Tailwind_merge dedoublonne les classes Tailwind en conflit dans Twig. Découvrez comment ce filtre rend vos composants plus prévisibles et maintenables.

MAJ 4 min de lecture
Sommaire · 7

Le filtre tailwind_merge résout un problème spécifique : quand vous construisez des composants Twig réutilisables avec Tailwind CSS, les classes entrent en conflit. Ce filtre, fourni par le bundle tales-from-a-dev/twig-tailwind-extra, détermine automatiquement quelle classe doit l'emporter.

Le problème des classes en double

Voici ce qui se passe sans tailwind_merge. Vous créez un composant bouton avec des styles par défaut :

Twig
<button class="p-4 text-gray-500 {{ attributes.render('class') }}">
    Click me
</button>

Imaginez que vous repassez quatre semaines plus tard sur le composant pour faire une modification :

Twig
{% embed 'Button.html.twig' with { attributes: { class: 'p-2 text-blue-600' } } %}

Le HTML généré contient maintenant class="p-4 text-gray-500 p-2 text-blue-600". Quelle classe gagne ? Ça dépend de l'ordre dans lequel Tailwind génère le CSS, pas de l'ordre dans le HTML. Résultat : vous ne pouvez pas prédire si le bouton aura padding: 1rem ou padding: 0.5rem.

Ce n'est pas une erreur JavaScript qui plante. C'est pire : c'est un bug visuel qui passe inaperçu jusqu'à ce qu'un utilisateur le remarque en production.

Comment fonctionne tailwind_merge

Le filtre analyse les classes Tailwind et garde la dernière classe de chaque "groupe". Un groupe correspond à une propriété CSS : toutes les classes p- contrôlent le padding, toutes les classes text--500 contrôlent la couleur du texte.

Twig
{{ ('p-4 text-gray-500 ' ~ attributes.render('class'))|tailwind_merge }}

Avec attributes.class = 'p-2 text-blue-600', vous obtenez p-2 text-blue-600. La classe p-2 écrase p-4, et text-blue-600 écrase text-gray-500. C'est tout.

La règle est simple : dernière classe du groupe = classe appliquée.

Application dans mes composants

Dans Button.html.twig, le composant combine les classes générées par un système de variants avec les classes personnalisées :

Twig
<{{ as }} data-slot="button"
    class="{{ style.apply({ variant: variant, size: size }, attributes.render('class'))|tailwind_merge }}"
    {{ attributes }}>
    {%- block content %}{% endblock -%}
</{{ as }}>

style.apply() génère des classes selon la variante (primary, secondary) et la taille (sm, lg). attributes.render('class') ajoute ce que l'appelant a passé. Le filtre élimine les conflits.

Pour un composant plus simple comme Card.html.twig :

Twig
<div class="{{ ('rounded-lg border bg-card text-card-foreground shadow-sm ' ~ attributes.render('class'))|tailwind_merge }}" {{ attributes }}>
    {%- block content %}{% endblock -%}
</div>

Les classes de base définissent l'apparence standard. Si quelqu'un passe border-2, ça écrase border. Si quelqu'un passe shadow-lg, ça écrase shadow-sm.

Le pattern à retenir

Chaque fois qu'un composant accepte des classes via attributes, utilisez cette structure :

Twig
{{ ('classes-de-base ' ~ attributes.render('class'))|tailwind_merge }}

Les classes de base viennent en premier. Les classes personnalisées viennent après. Le filtre gère les conflits.

Ce que ça change concrètement

Avant tailwind_merge, vous deviez créer des props pour chaque variation possible. Un composant Card avait besoin de borderWidth, shadowSize, rounded, etc. Ou alors vous acceptiez que les overrides de classes soient aléatoires.

Avec tailwind_merge, vous écrivez un seul composant avec des classes de base raisonnables. Les développeurs passent les classes qui diffèrent. Le filtre fait le tri.

Moins de props à maintenir. Moins de variantes à documenter. Moins de bugs visuels mystérieux.

Installation et utilisation

Le filtre vient avec tales-from-a-dev/twig-tailwind-extra, qui encapsule tailwind-merge-php. Une fois le bundle installé, tailwind_merge est disponible partout dans vos templates Twig.

tailwind_merge repose sur une connaissance interne de la structure de Tailwind. Il sait que p- et px- appartiennent au même système de propriétés (padding). Il sait que text-gray-500 et text-blue-600 contrôlent la couleur du texte. Il sait résoudre les conflits entre rounded-lg et rounded-none.

Cette connaissance est encodée dans la bibliothèque. Vous n'avez pas à lui expliquer quelles classes entrent en conflit. Elle le sait déjà.

Le mot de la fin

tailwind_merge prend un comportement imprévisible (plusieurs classes qui se contredisent) et applique une règle claire (la dernière gagne). Pour les projets qui combinent Twig et Tailwind, c'est un outil qui réduit les frictions et rend les composants plus fiables. Pas révolutionnaire, mais utile tous les jours.

Activez uniquement ce que vous souhaitez. Vos choix sont conservés 6 mois.

Strictement nécessaires

Indispensables au fonctionnement du site (session, sécurité, préférence d'affichage). Aucune donnée n'est partagée à des tiers et aucun consentement n'est requis.

Toujours actif

Mesure d'audience

Statistiques via Google Analytics (GA4) : pages vues, source du trafic, navigateur et interactions clés. Dépose des cookies de mesure, activés seulement avec votre accord (Consent Mode). Sans publicité ciblée, sans Google Signals, sans partage commercial.

Contenus externes

Affiche les GIF animés hébergés par Giphy (CDN aux États-Unis). À l'affichage d'un GIF, votre adresse IP et votre navigateur sont transmis à Giphy. Sans votre accord, les GIF ne s'affichent pas.