Une bibliothèque de composants Twig headless (sans style) inspirée de Radix UI, avec interactivité Stimulus.
Les composants ne contiennent aucun style CSS imposé. Vous gardez le contrôle total sur l'apparence :
- Utilisez Tailwind, Bootstrap, ou votre propre CSS
- Appliquez vos classes via l'attribut
class - Personnalisez avec
styleinline si nécessaire
- Attributs ARIA automatiques (
role,aria-live,aria-label) - Navigation au clavier gérée par les controllers Stimulus
- Sémantique HTML correcte
<twig:Alert:Alert variant="success" dismissible>
Contenu de l'alerte
</twig:Alert:Alert>Affiche des messages importants à l'utilisateur.
| Prop | Type | Défaut | Description |
|---|---|---|---|
variant |
string |
'info' |
Type d'alerte : info, success, warning, error |
dismissible |
bool |
false |
Permet de fermer l'alerte |
title |
string |
null |
Titre optionnel |
icon |
string |
null |
Icône ou emoji à afficher |
Alerte simple
<twig:Alert:Alert variant="info">
Votre session expire dans 5 minutes.
</twig:Alert:Alert>Alerte dismissible
<twig:Alert:Alert variant="success" title="Succès" dismissible>
Vos modifications ont été enregistrées.
</twig:Alert:Alert>Avec Tailwind CSS
<twig:Alert:Alert
variant="error"
dismissible
class="bg-red-50 border-l-4 border-red-500 p-4 rounded"
>
Une erreur s'est produite.
</twig:Alert:Alert>Le composant expose ces attributs pour le ciblage CSS :
[data-variant="..."]: Le variant de l'alerte[data-alert-title]: Le conteneur du titre[data-alert-content]: Le conteneur du contenu
Le controller Stimulus émet ces événements :
alert:dismiss: Avant la fermeture (cancelable)alert:dismissed: Après la fermeture
document.addEventListener('alert:dismissed', (event) => {
console.log('Alert dismissed:', event.detail.element);
});Composant collapsible pour organiser du contenu en sections pliables.
| Prop | Type | Défaut | Description |
|---|---|---|---|
type |
string |
'single' |
Mode : single (un seul ouvert) ou multiple (plusieurs ouverts) |
collapsible |
bool |
true |
Permet de fermer tous les items en mode single |
defaultValue |
string |
null |
Valeur de l'item ouvert par défaut |
| Prop | Type | Défaut | Description |
|---|---|---|---|
value |
string |
auto | Identifiant unique de l'item |
title |
string |
null |
Titre du bouton déclencheur |
disabled |
bool |
false |
Désactive l'item |
Accordion simple
<twig:Accordion:Accordion type="single">
<twig:Accordion:AccordionItem value="item1" title="Section 1">
Contenu de la section 1
</twig:Accordion:AccordionItem>
<twig:Accordion:AccordionItem value="item2" title="Section 2">
Contenu de la section 2
</twig:Accordion:AccordionItem>
</twig:Accordion:Accordion>Mode multiple avec item par défaut
<twig:Accordion:Accordion type="multiple" defaultValue="faq1">
<twig:Accordion:AccordionItem value="faq1" title="Question 1">
Réponse 1
</twig:Accordion:AccordionItem>
<twig:Accordion:AccordionItem value="faq2" title="Question 2">
Réponse 2
</twig:Accordion:AccordionItem>
</twig:Accordion:Accordion>Avec styling personnalisé
<twig:Accordion:Accordion class="space-y-2">
<twig:Accordion:AccordionItem
value="styled"
title="Item stylisé"
class="border rounded-lg shadow-sm"
>
Du contenu stylisé avec vos classes CSS
</twig:Accordion:AccordionItem>
</twig:Accordion:Accordion>↓/↑: Naviguer entre les itemsHome/End: Aller au premier/dernier itemEnter/Space: Toggle l'item courant
[data-accordion-item]: Conteneur de l'item[data-accordion-trigger]: Bouton déclencheur[data-accordion-content]: Contenu collapsible[data-accordion-icon]: Icône de l'état (rotatable)
accordion:open: Quand un item s'ouvreaccordion:close: Quand un item se ferme
document.addEventListener('accordion:open', (event) => {
console.log('Item opened:', event.detail.value);
});Gère l'ajout et la suppression dynamique d'éléments dans les collections Symfony.
| Prop | Type | Défaut | Description |
|---|---|---|---|
prototype |
string |
null |
Le prototype HTML du formulaire (généré par Symfony) |
addLabel |
string |
'Ajouter' |
Texte du bouton d'ajout |
removeLabel |
string |
'Supprimer' |
Texte du bouton de suppression |
allowAdd |
bool |
true |
Permet d'ajouter des éléments |
allowRemove |
bool |
true |
Permet de supprimer des éléments |
addButtonClass |
string |
'' |
Classes CSS pour le bouton d'ajout |
removeButtonClass |
string |
'' |
Classes CSS pour le bouton de suppression |
{# Rendre le prototype une seule fois dans une variable #}
{% set emailPrototype %}
<div style="display: flex; gap: 0.5rem;">
{{ form_widget(form.emails.vars.prototype) }}
</div>
{% endset %}
<twig:FormCollection
prototype="{{ emailPrototype|e('html_attr') }}"
addLabel="➕ Ajouter un email"
addButtonClass="btn btn-primary"
>
{% for emailForm in form.emails %}
<div data-form-collection-item style="display: flex; gap: 0.5rem;">
{{ form_widget(emailForm) }}
{{ form_errors(emailForm) }}
</div>
{% endfor %}
</twig:FormCollection>Important : Le prototype doit être rendu dans une variable avec {% set %} pour éviter l'erreur "Field has already been rendered". Utilisez |e('html_attr') pour l'échapper correctement.
Utilisation directe avec les helpers Stimulus :
<div
{{ stimulus_controller('form-collection') }}
data-form-collection-prototype-value="{{ '<div><input name="items[__name__]" /></div>' }}"
data-form-collection-index-value="1"
>
<div {{ stimulus_target('form-collection', 'container') }}>
<div data-form-collection-item>
<input name="items[0]" />
<button {{ stimulus_action('form-collection', 'remove') }}>Supprimer</button>
</div>
</div>
<button {{ stimulus_action('form-collection', 'add') }}>Ajouter</button>
</div>form-collection:item-added: Quand un élément est ajoutéform-collection:item-removed: Quand un élément est suppriméform-collection:before-remove: Avant la suppression (cancelable)
document.addEventListener('form-collection:item-added', (event) => {
console.log('Nouvel élément:', event.detail.element);
});- ✅ Gestion automatique des indices (
__name__) - ✅ Animation de suppression
- ✅ Scroll automatique vers le nouvel élément
- ✅ Support des formulaires imbriqués
- ✅ Events personnalisables
- Accordion
- FormCollection
- Dialog / Modal
- Dropdown
- Tabs
- Tooltip
- Badge
- Card
src/Twig/Components/ # Classes PHP des composants
templates/components/ # Templates Twig
assets/controllers/ # Controllers Stimulus
- Composants : PascalCase (
Alert,Accordion) - Props : camelCase (
dismissible,variant) - Events : kebab-case (
alert:dismiss)
Tous les composants acceptent :
class: Classes CSS personnaliséesstyle: Styles inlineid: ID HTML- Tout autre attribut HTML via
{{ attributes }}