diff --git a/beesgospel/forms.py b/beesgospel/forms.py
index a0c5d67..c6be86c 100644
--- a/beesgospel/forms.py
+++ b/beesgospel/forms.py
@@ -4,7 +4,7 @@ from django import forms
 from django.contrib.auth import forms as auth_forms
 from django.db import transaction
 
-from .models import Chant, Membre, User
+from .models import Chant, ChantDoc, Membre, User
 
 
 class BootstrapMixin:
@@ -59,3 +59,20 @@ class ChantEditForm(BootstrapMixin, forms.ModelForm):
     class Meta:
         model = Chant
         fields = ["numero", "titre", "particularite"]
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        self.formset = None
+        if self.instance.pk:
+            DocFormSet = forms.inlineformset_factory(Chant, ChantDoc, fields=["fichier", "titre"], extra=1)
+            self.formset = DocFormSet(data=kwargs.get("data"), files=kwargs.get("files"), instance=self.instance)
+
+    def is_valid(self):
+        return all([super().is_valid()] + [self.formset.is_valid()] if self.formset else [])
+
+    @transaction.atomic()
+    def save(self, **kwargs):
+        obj = super().save(**kwargs)
+        if self.formset:
+            self.formset.save()
+        return obj
diff --git a/beesgospel/migrations/0007_chantdoc.py b/beesgospel/migrations/0007_chantdoc.py
new file mode 100644
index 0000000..8336b84
--- /dev/null
+++ b/beesgospel/migrations/0007_chantdoc.py
@@ -0,0 +1,21 @@
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('beesgospel', '0006_chant'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ChantDoc',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('fichier', models.FileField(blank=True, upload_to='chants', verbose_name='Fichier')),
+                ('titre', models.CharField(max_length=200, verbose_name='Titre')),
+                ('chant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='beesgospel.chant')),
+            ],
+        ),
+    ]
diff --git a/beesgospel/models.py b/beesgospel/models.py
index 3457239..e9cafe2 100644
--- a/beesgospel/models.py
+++ b/beesgospel/models.py
@@ -118,3 +118,12 @@ class Chant(models.Model):
 
     def __str__(self):
         return f"{self.numero}. {self.titre}"
+
+
+class ChantDoc(models.Model):
+    chant = models.ForeignKey(Chant, on_delete=models.CASCADE)
+    fichier = models.FileField("Fichier", upload_to="chants", blank=True)
+    titre = models.CharField("Titre", max_length=200)
+
+    def __str__(self):
+        return f"Document {self.titre} pour le chant {self.chant}"
diff --git a/beesgospel/static/ficons/README b/beesgospel/static/ficons/README
new file mode 100644
index 0000000..e9cca77
--- /dev/null
+++ b/beesgospel/static/ficons/README
@@ -0,0 +1,2 @@
+Many thanks to Daniel M. Hendricks, http://daniel.hn
+https://github.com/dmhendricks/file-icon-vectors/
diff --git a/beesgospel/static/ficons/docx.svg b/beesgospel/static/ficons/docx.svg
new file mode 100644
index 0000000..ac084a0
--- /dev/null
+++ b/beesgospel/static/ficons/docx.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/beesgospel/static/ficons/image.svg b/beesgospel/static/ficons/image.svg
new file mode 100644
index 0000000..8d4cac8
--- /dev/null
+++ b/beesgospel/static/ficons/image.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/beesgospel/static/ficons/master.svg b/beesgospel/static/ficons/master.svg
new file mode 100644
index 0000000..2537cbe
--- /dev/null
+++ b/beesgospel/static/ficons/master.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/beesgospel/static/ficons/mp3.svg b/beesgospel/static/ficons/mp3.svg
new file mode 100644
index 0000000..7d5a0a8
--- /dev/null
+++ b/beesgospel/static/ficons/mp3.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/beesgospel/static/ficons/odt.svg b/beesgospel/static/ficons/odt.svg
new file mode 100644
index 0000000..f30088b
--- /dev/null
+++ b/beesgospel/static/ficons/odt.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/beesgospel/static/ficons/pdf.svg b/beesgospel/static/ficons/pdf.svg
new file mode 100644
index 0000000..e6472df
--- /dev/null
+++ b/beesgospel/static/ficons/pdf.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/beesgospel/static/ficons/tsv.svg b/beesgospel/static/ficons/tsv.svg
new file mode 100644
index 0000000..318ba05
--- /dev/null
+++ b/beesgospel/static/ficons/tsv.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/beesgospel/static/js/main.js b/beesgospel/static/js/main.js
index cbd6606..3ec05b6 100644
--- a/beesgospel/static/js/main.js
+++ b/beesgospel/static/js/main.js
@@ -11,4 +11,7 @@ window.addEventListener('DOMContentLoaded', () => {
         let resp = confirm("Voulez-vous vraiment supprimer cette ligne ?");
         if (!resp) { ev.preventDefault(); ev.stopImmediatePropagation(); }
     });
+
+    const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
+    const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
 })
diff --git a/beesgospel/templatetags/bees_utils.py b/beesgospel/templatetags/bees_utils.py
new file mode 100644
index 0000000..6c58526
--- /dev/null
+++ b/beesgospel/templatetags/bees_utils.py
@@ -0,0 +1,27 @@
+from pathlib import Path
+
+from django.template import Library
+from django.templatetags.static import static
+
+IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".tif", ".tiff", ".gif"]
+
+register = Library()
+
+
+@register.filter
+def icon_url(file_name):
+    ext = Path(file_name).suffix.lower()
+    icon = "master"  # default
+    if ext in IMAGE_EXTS:
+        icon = "image"
+    elif ext == ".pdf":
+        icon = "pdf"
+    elif ext in [".mp3", ".wav"]:
+        icon = "mp3"
+    elif ext in (".xls", ".xlsx", ".ods", ".csv"):
+        icon = "tsv"
+    elif ext == ".odt":
+        icon = "odt"
+    elif ext in (".doc", ".docx"):
+        icon = "docx"
+    return static(f"ficons/{icon}.svg")
diff --git a/beesgospel/views.py b/beesgospel/views.py
index 53b26a2..fc7619f 100644
--- a/beesgospel/views.py
+++ b/beesgospel/views.py
@@ -115,7 +115,7 @@ class ListeChantsView(LoginRequiredMixin, ListView):
     template_name = "membres/liste_chants.html"
 
     def get_queryset(self):
-        return super().get_queryset().order_by("numero")
+        return super().get_queryset().prefetch_related("chantdoc_set").order_by("numero")
 
 
 class ChantAddView(PermissionRequiredMixin, CreateView):
diff --git a/templates/membres/chant_edit.html b/templates/membres/chant_edit.html
index bb439d2..3420565 100644
--- a/templates/membres/chant_edit.html
+++ b/templates/membres/chant_edit.html
@@ -3,8 +3,19 @@
 {% block content %}
     
Édition/ajout de chant
 
-    
 {% endblock content %}
diff --git a/templates/membres/liste_chants.html b/templates/membres/liste_chants.html
index 0d2c1ef..561fa3e 100644
--- a/templates/membres/liste_chants.html
+++ b/templates/membres/liste_chants.html
@@ -1,23 +1,31 @@
 {% extends "base.html" %}
+{% load bees_utils %}
 
 {% block content %}
     Liste des chants
-    
-        | N° | Titre |  |  | 
+    
+        | N° | Titre |  |  | 
+            {% if perms.beesgospel.change_chant %} | {% endif %}
     {% for chant in object_list %}
         
             | {{ chant.numero }} | 
             {{ chant.titre }} | 
+            {% for doc in chant.chantdoc_set.all %}
+                
+                     
+                {% endfor %}
+             | 
             {{ chant.particularite }} | 
-            {% if perms.beesgospel.change_chant %}
+            {% if perms.beesgospel.change_chant %}
+             | 
                 
                      
                 
                 
-                {% endif %}
              | 
+            {% endif %}
         
     {% endfor %}