Composants Vue.js

Props, Emits & Slots

C141 — Séance 6 — 5 mars 2026

Flèches pour naviguer

Code de départ

Ouvrez le playground Vue.js et codez avec moi !

Ouvrir le Playground Vue.js

play.vuejs.org — aucun compte requis

Objectifs de la séance

🧩

Composants

Découper une application en morceaux réutilisables et indépendants

⬇️

Props

Passer des données du parent vers l'enfant avec defineProps()

⬆️

Emits

Communiquer de l'enfant vers le parent avec defineEmits()

📦

Slots

Injecter du contenu HTML dans un composant enfant

Pourquoi des composants ?

Une application Vue.js est un arbre de composants imbriqués, comme des poupées russes.

Chaque composant est un fichier .vue autonome avec son propre template, script et style.

Réutilisable — un composant peut être utilisé partout
Maintenable — chaque fichier a une responsabilité
Testable — on peut tester chaque composant seul
App.vue
Header.vue
Main.vue
Footer.vue
NavBar.vue
Card.vue
Button.vue
Logo.vue

Créer et utiliser un composant

ChildComp.vue

<template>
<p>Un composant enfant !</p>
</template>

Un fichier .vue = un composant autonome

App.vue

<script setup>
// 1. Importer le composant
import ChildComp from './ChildComp.vue'
</script>
<template>
<!-- 2. Utiliser comme une balise HTML -->
<ChildComp />
</template>

Avec <script setup>

Le composant importé est automatiquement disponible dans le template. Pas besoin de l'enregistrer !

Rendu : <p>Un composant enfant !</p>

Props — Parent → Enfant

Les props permettent de passer des données du composant parent vers le composant enfant

Parent
const msg = ref("Salut")
:msg="msg"
Enfant
defineProps({ msg: String })

Déclarer les props dans l'enfant

defineProps() est une macro — pas besoin de l'importer

Passer les props depuis le parent

Valeur statique : msg="Salut"

Valeur dynamique : :msg="variable"

Lecture seule

Les props sont en lecture seule. L'enfant ne peut pas modifier une prop !

Props — Exemple complet

App.vue (parent)

<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'
const greeting = ref('Hello du parent')
</script>
<template>
<ChildComp :msg="greeting" />
</template>

ChildComp.vue (enfant)

<script setup>
defineProps({
msg: String
})
</script>
<template>
<p>{{ msg }}</p>
</template>

Rendu : <p>Hello du parent</p>

Emits — Enfant → Parent

Les emits permettent à l'enfant d'envoyer des événements au parent

Parent
@response="(msg) => childMsg = msg"
emit('response', data)
Enfant
defineEmits(['response'])

1. L'enfant déclare ses événements

const emit = defineEmits(['response'])

2. L'enfant émet un événement

emit('response', "hello de l'enfant")

3. Le parent écoute l'événement

<ChildComp @response="handleResponse" />

Emits — Exemple complet

ChildComp.vue (enfant)

<script setup>
const emit = defineEmits(['response'])
// Émettre l'événement
emit('response', "hello de l'enfant")
</script>
<template>
<p>Composant enfant</p>
</template>

App.vue (parent)

<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'
const childMsg = ref("Pas encore de message")
</script>
<template>
<ChildComp @response="(msg) => childMsg = msg" />
<p>{{ childMsg }}</p>
</template>

Rendu : <p>hello de l'enfant</p>

Slots — Injection de contenu

Les slots permettent au parent d'injecter du HTML dans le template de l'enfant

Analogie : le cadre photo

Un composant avec un slot, c'est comme un cadre photo : le cadre est toujours le même, mais on peut y mettre n'importe quelle photo.

Slot par défaut

Le contenu principal injecté dans <slot />

Slots nommés

Plusieurs emplacements : <slot name="header" />

Contenu de secours

Affiché si aucun contenu n'est fourni : <slot>Fallback</slot>

Parent
<Card>
Mon contenu ici
</Card>
Card.vue
<div class="card">
<slot /> ← "Mon contenu ici"
</div>

Slots — Exemple complet

ChildComp.vue (enfant)

<template>
<div class="card">
<slot>Contenu de secours</slot>
</div>
</template>

Si le parent ne fournit pas de contenu, "Contenu de secours" est affiché

App.vue (parent)

<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'
const msg = ref('depuis le parent')
</script>
<template>
<ChildComp>
Message: {{ msg }}
</ChildComp>
</template>

Rendu : <div class="card">Message: depuis le parent</div>

Récapitulatif — Communication entre composants

⬇️

Props

Parent → Enfant

defineProps({
msg: String
})

Données en lecture seule

⬆️

Emits

Enfant → Parent

const emit =
defineEmits(['event'])
emit('event', data)

Événements personnalisés

📦

Slots

Injection de contenu

<slot>
Fallback
</slot>

HTML flexible et réutilisable

Mécanisme Direction Type de données Cas d'usage
Props Parent → Enfant String, Number, Object, Array... Configurer un composant
Emits Enfant → Parent Événements + arguments Notifier le parent d'une action
Slots Parent → Enfant HTML / Composants Personnaliser le rendu

Exercices pratiques

1

Tutoriel Vue.js — Étapes 11 à 14

Complétez les 4 étapes du tutoriel officiel pour pratiquer les concepts

11 — Composants
12 — Props
13 — Emits
14 — Slots
→ fr.vuejs.org/tutorial/#step-11
2

Exercice 8 — Liste de Pokémon avec composants

Créez un composant PokemonCard.vue qui :

  • Reçoit le nom du Pokémon en prop
  • Affiche le Pokémon avec v-for
  • Émet un événement emit pour supprimer un Pokémon
3

Exercice 9 — Slots nommés et par défaut

Créez un composant CarteAvecSlots.vue avec :

  • Un slot nommé header pour le titre
  • Un slot par défaut pour le contenu principal
  • Un slot nommé footer pour les actions
  • Du contenu de secours (fallback) si le slot est vide

Ressources