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.
Catégorie

DX

Marre des environnements de dev frustrants et des outils qui ralentissent votre workflow ? Améliorez votre quotidien avec des méthodes qui remettent enfin le plaisir au cœur du code.

Lecture
4 min
Niveau
Intermédiaire
janv 25 2026
Partager

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.

Poursuivre la lecture

Sélectionné avec soin pour vous.

DX

Symfony UX Toolkit : quand le frontend devient (enfin) un plaisir

Découvrez comment Symfony UX Toolkit et le kit Shadcn révolutionnent le frontend.

4 min de lecture
UX

AssetMapper : le frontend pour ceux qui détestent (vraiment) le frontend

Oubliez Webpack ! AssetMapper utilise les importmap natifs pour gérer vos assets (JS, CSS) dans Symfony. Zéro build, zéro Node.js.

9 min de lecture
DevOps

Comment j'ai industrialisé mon side-project avec Google Jules

Ne laissez plus l'IA "deviner" si le code fonctionne. Apprenez à configurer une sandbox Docker pour Google Jules afin d'automatiser la QA, la sécurité et la performance, loin du "Vibe Coding".

5 min de lecture