Symfony UX Icons : 200 000 icônes SVG sans CDN, sans sprite, sans prise de tête
Publié le
Temps de lecture 6 min
Vous connaissez la chanson : votre graphiste vous envoie enfin les maquettes. Vous récupérez les SVG, vous tentez de les optimiser, et c'est là que le cauchemar commence.
Vous passez esnuite deux heures à hésiter entre un CDN Font Awesome qui plombe vos perfs, la création manuelle d'un sprite SVG ingérable, ou le copier-coller sauvage de fichiers dans /public/icons/ ? Vous avez déjà pesté parce que l'icône parfaite n'existait pas, ou parce que le chargement d'une police de 300 Ko bloquait le rendu de votre page pour trois malheureux logos ?
Si vous développez avec Symfony en 2025, ce temps est révolu.
Symfony UX Icons ne se contente pas de régler le problème, il le supprime. Il propose une approche radicale : 200 000+ icônes SVG disponibles instantanément, intégrées via Iconify, sans CDN, sans sprite à maintenir, sans fichier à copier manuellement. Une ligne Twig, zéro configuration.
Aide-mémoire
Pour les développeurs pressés, voici l'essentiel à retenir :
| Action | Commande / Code |
|---|---|
| Installation | composer require symfony/ux-icons |
| Usage Twig | {{ ux_icon('tabler:search', { class: 'w-5 h-5' }) }} |
| Recherche | Iconify Sets (Cherchez, copiez le nom, collez) |
| Cache Clear | php bin/console cache:clear (si une icône ne se met pas à jour) |
Le problème de la gestion d'icônes
Avant l'arrivée d'UX Icons, nous devions choisir entre trois maux :
1. Font Awesome CDN
<link rel="stylesheet" href="[https://cdn.fontawesome.com/](https://cdn.fontawesome.com/)..." />
<i class="fa-solid fa-magnifying-glass"></i>
Le verdict : C'est l'assassin de votre score Lighthouse. Vous chargez une librairie entière (CSS + Fonts) pour afficher 10 icônes.
2. SVG Sprites
<svg><use xlink:href="/sprites/icons.svg#search"></use></svg>
Le verdict : Performant, mais horrible à maintenir. Ajouter une icône demande de régénérer le sprite. Le fichier devient vite monolithique et le styling (fill/stroke) est limité.
3. Fichiers SVG manuels
<img src="{{ asset('icons/search.svg') }}" alt="Recherche" />
Le verdict : Vous finissez avec 200 fichiers dans un dossier, sans convention de nommage claire. De plus, la balise empêche de manipuler le CSS interne du SVG (couleur au survol, épaisseur du trait). Le constat est sans appel : Soit vous sacrifiez les performances (CDN), soit vous sacrifiez la maintenabilité (Fichiers/Sprites).
Qu'est-ce que Symfony UX Icons ?
Symfony UX Icons fait partie de l'écosystème Symfony UX. C'est le pont intelligent entre Iconify (la plus grande agrégation d'icônes open source au monde) et votre application Symfony.
Le mécanisme magique
Au lieu de charger des icônes via le réseau, UX Icons fonctionne en 3 étapes invisibles :
- Téléchargement local : Au premier usage (en dev) ou au build (en prod), Symfony télécharge le SVG brut depuis l'API Iconify.
- Mise en cache : Le SVG est stocké dans le cache Symfony.
- Injection Inline : Le SVG est injecté directement dans votre HTML.
Résultat : Vous écrivez {{ ux_icon('tabler:search') }} et Symfony génère le code <svg>...</svg> optimisé.
Pourquoi Iconify change la donne ?
Iconify unifie 150+ collections. Vous n'êtes plus marié à une seule charte graphique. Vous avez accès à :
- Tabler Icons (5200+, style ligne épurée)
- Lucide (1400+, le successeur de Feather)
- Material Design Icons (7500+, Google officiel)
- Heroicons, Bootstrap Icons, Font Awesome, et des centaines d'autres.
Besoin du logo LinkedIn ? tabler:brand-linkedin. D'un chevron spécifique ? lucide:chevron-right. Tout est là.
Installation et Configuration
composer require symfony/ux-icons
Symfony Flex génère automatiquement config/packages/ux_icons.yaml. Voici la configuration que j’utilise :
ux_icons:
default_icon_attributes:
# Permet de contrôler la couleur via le CSS parent (ex: text-red-500)
fill: currentColor
# Taille relative à la police par défaut
height: '1em'
width: '1em'
# En prod, on ne veut pas qu'une icône manquante fasse planter la page
ignore_not_found: false
when@prod:
ux_icons:
ignore_not_found: true
Le secret de la performance : le cache
Les icônes sont stockées dans var/cache/ux_icons/. Avec une stack moderne (FrankenPHP + Redis), ce cache est persistant. Zéro latence, zéro appel API en production. C'est 100% local.
Stratégie de design
Sur lecodeestdanslepre.fr, j’adopté une stratégie hybride pour combler les manques de chaque librairie.
1. La base : Tabler Icons
90% du site utilise Tabler pour son style "outline" très propre et moderne.
- Usage : Navigation, actions utilisateur, réseaux sociaux (tabler:brand-...).
- Astuce : Je force souvent 'stroke-width': 2 pour un rendu plus affirmé.
2. Le complément : Lucide
Lucide est utilisé quand Tabler n'a pas l'icône parfaite. Le style est très proche de Tabler, le mélange est invisible à l'œil nu.
- Usage : Interface UI (
lucide:more-horizontalpour les menus ellipsis).
3. L'exception : Material Design (MDI)
Utilisé très rarement pour des formes pleines ou spécifiques que seule la bibliothèque de Google possède.
Exemples d'implémentation
Voici comment j’utilise UX Icons dans mes templates Twig, couplé à Tailwind CSS.
1. Header avec animation au survol
{# Lien Recherche #}
<a href="{{ path('app_search') }}"
class="group p-3 text-gray-900 hover:bg-gray-100 rounded-lg"
aria-label="Rechercher">
{{ ux_icon('tabler:search', {
class: 'h-5 w-5 transition-transform duration-300 group-hover:scale-110',
'stroke-width': 2
}) }}
</a>
Notez l'usage de group-hover:scale-110 : comme c'est un SVG inline, on peut l'animer (zoom, rotation, couleur) directement en CSS !
2. Pagination (Mélange Tabler & Lucide)
{# Précédent (Tabler) #}
<button class="flex items-center gap-2">
{{ ux_icon('tabler:chevron-left', { class: 'h-4 w-4' }) }}
<span>Précédent</span>
</button>
{# Séparateur "..." (Lucide, car meilleur design que Tabler sur ce point) #}
<span class="text-gray-400">
{{ ux_icon('lucide:more-horizontal', { class: 'h-5 w-5' }) }}
</span>
3. Dark Mode natif
Grâce à fill: currentColor configuré globalement, la gestion du thème sombre est triviale :
<div class="text-gray-600 dark:text-gray-300">
{# L'icône sera grise le jour, et gris clair la nuit #}
{{ ux_icon('tabler:user', { class: 'h-6 w-6' }) }}
</div>
Tableau de décision
Est-ce fait pour vous ?
| Solution | Requêtes | Poids | Flexibilité | Verdict |
|---|---|---|---|---|
| UX Icons | 0 | ~1kb / icône | Totale (200k choix) | ⭐⭐⭐⭐⭐ |
| Font Awesome CDN | 2 | 300kb+ | Faible | ⭐⭐ |
| Sprites SVG | 1 | Variable | Moyenne (Maintenance !) | ⭐⭐⭐ |
| SVG "à la main" | Multiples | Léger | Nulle (Copier/Coller) | ⭐⭐ |
Seul cas limite : Si vous avez un Design System propriétaire très strict avec des icônes dessinées sur mesure par vos graphistes, un système de composants Twig dédiés ou un sprite custom reste pertinent. Pour les 99% d'autres projets : UX Icons gagne.
3 règles d'or pour réussir son intégration
Pour éviter les pièges que j’ai rencontrés, suivez ces règles :
- Toujours préfixer le nom de la collection :
{{ ux_icon('search') }}(Ambigu, plantera){{ ux_icon('tabler:search') }}(Clair et robuste)
- Maîtriser le "Stroke Width" :
Les icônes Tabler sont parfois fines par défaut (1.5px). Sur des petites tailles (16px), forcez le trait à 2px pour la lisibilité :
{{ ux_icon('tabler:check', { 'stroke-width': 2 }) }} - Accessibilité (A11y) :
Si l'icône est seule (bouton fermer), mettez un aria-label sur le bouton. Si l'icône est décorative (à côté d'un texte), ajoutez aria-hidden="true" via les attributs :
{{ ux_icon('tabler:star', { 'aria-hidden': 'true' }) }}
Le mot de la fin
Symfony UX Icons a rendu la gestion d'icônes invisible, et c'est le meilleur compliment qu'on puisse faire à une technologie.
Nous ne gérons plus de fichiers. Nous ne gérons plus de versions de CDN. Nous cherchons une icône, nous la nommons, elle s'affiche. C'est performant par défaut, accessible par design, et incroyablement flexible.