Creating a Vue project
Vue is a progressive JavaScript framework for building interfaces: you can add it to an existing page or build a full application. The recommended starting point is the official create-vue tool, based on Vite:
npm create vue@latest # questions: TypeScript, then Router, Pinia, Vitest…
cd mon-projet
npm install
npm run dev # Vite dev server with hot reload
The project uses Vue 3.5 and Vite 8 (Node.js 22.18 or later; the current LTS, Node 26, works). The first question, “Use TypeScript?”, is checked Yes by default: since this course is written in JavaScript, answer No. You can also specify everything on the command line: npm create vue@latest mon-projet -- --router --pinia --vitest directly creates a JavaScript project with these options (add --ts for TypeScript).
The project contains src/main.js, which creates the application (createApp(App).mount('#app')), and .vue files: single-file components (SFCs).
Anatomy of a component
<script setup>
import { ref } from 'vue'
const titre = 'Mes tâches'
const taches = ref([
{ id: 1, libelle: 'Acheter du pain', faite: false },
{ id: 2, libelle: 'Réviser Vue', faite: true },
])
function basculer(tache) {
tache.faite = !tache.faite
}
</script>
<template>
<h1>{{ titre }}</h1>
<ul>
<li v-for="tache in taches" :key="tache.id" :class="{ faite: tache.faite }">
<label>
<input type="checkbox" :checked="tache.faite" @change="basculer(tache)" />
{{ tache.libelle }}
</label>
</li>
</ul>
<p v-if="taches.length === 0">No tasks.</p>
</template>
<style scoped>
.faite { text-decoration: line-through; }
</style>
<script setup>is the recommended syntax with the Composition API: any variable, function or component imported there is directly available in the template.<template>describes the HTML, enriched with Vue’s syntax.<style scoped>limits the styles to this component.
ref() makes a value reactive: when it changes, Vue updates the display. The next lesson covers reactivity in detail.
Interpolation and bindings
{{ expression }}displays a JavaScript expression (not a statement: noiforfor).v-bind:attributor its shorthand:attributbinds an attribute to an expression::disabled="panierVide",:href="url".v-on:evenementor@evenementlistens to an event:@click="ajouter",@submit.prevent="envoyer"(the.preventmodifier callspreventDefault()).v-modelcreates a two-way binding with a field:<input v-model="recherche" />.
Conditional rendering and lists
v-if / v-else-if / v-else create or destroy the element; v-show keeps it in the DOM and hides it with display: none. Prefer v-show for an element toggled very often, v-if for content that is rarely displayed or expensive.
v-for repeats an element for each entry of a list. It requires a unique, stable :key, typically the item’s identifier. With the index as the key, Vue reuses the wrong elements when you sort or delete, and internal state (a field being typed in) ends up on the wrong row. Also avoid v-if and v-for on the same element: filter the list upstream instead.
Dynamic classes and styles
:class accepts an object (the class is applied if the value is truthy) or an array:
<button :class="['btn', `btn--${variante}`, { 'btn--desactive': desactive }]">
Extracting display logic
A template should stay readable. As soon as an expression becomes complex (filtering by a criterion, building classes, formatting a label), put it in a pure function: it receives data and returns a result, with no side effects. It can be tested without a browser and reused:
// src/logique/taches.js
export function filtrerTaches(taches, filtre) {
if (filtre === 'actives') return taches.filter((t) => !t.faite)
if (filtre === 'faites') return taches.filter((t) => t.faite)
return taches
}
The component then uses it in the template or, better, in a computed property (computed), covered in the next lesson. This is what you will practice in this course’s code exercises: logic in plain JavaScript, components in hands-on tasks.
Takeaways
Component = script + template + style. : to bind, @ to listen, v-if/v-show to display, v-for with a stable :key to repeat, and display logic extracted into pure functions.
Exercises
Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.
Filter a task list
Logic used by the list component. Write:
filtrerTaches(taches, filtre)which returns all the tasks for"toutes", the incomplete tasks for"actives", the completed tasks for"faites". An unknown filter throws an errorFiltre inconnu.libelleRestantes(taches)which returns"Aucune tâche restante","1 tâche restante"or"N tâches restantes".
Never modify the array received.
function filtrerTaches(taches, filtre) { // TODO } function libelleRestantes(taches) { // TODO }Button classes
The
BoutonAppcomponent computes its list of classes for:class. WriteclassesBouton(options)which receives an object{ variante, taille, desactive }(all properties optional) and returns an array:- always
"btn"; "btn--<variante>"withvariantedefaulting to"primaire"; only"primaire","secondaire"and"danger"are accepted, otherwise an errorVariante inconnue;"btn--<taille>"withtailledefaulting to"m";"btn--desactive"last, only ifdesactiveis truthy.
function classesBouton(options = {}) { // TODO }- always
First component: the task list
Create a project with
npm create vue@latest(answer No to TypeScript and check no feature), then replace the content ofApp.vuewith a task list component:- Initial data (in a
ref):
id,libelle,faite 1,Acheter du pain,false 2,Réviser Vue,true 3,Appeler le garage,false- Display each task with a checkbox bound to
faite, usingv-forand:key="tache.id". - Add three filter buttons (Toutes, Actives, Faites) that use your
filtrerTachesfunction. - Display below the list the text produced by
libelleRestantes.
- v-for uses :key with the task identifier
- The filter buttons change the displayed list without modifying the data
- Checking a task updates the counter immediately
- The filter and label functions are imported from a separate .js file
- Initial data (in a
v-if or v-show?
A help panel is opened and closed very often by the user. Which directive is the most suitable, and why?
- v-if, because it is faster on every toggle
- v-show, because the element stays in the DOM and only its CSS visibility changes
- v-for, to repeat the panel
- No difference between the two
End-of-lesson quiz
What does
:disabled="panierVide"do?- It gives the attribute the string "panierVide"
- It binds the disabled attribute to the value of the panierVide expression
- It listens to the disabled event
Why avoid the index as :key in a v-for?
- It is forbidden by Vue
- When the list is sorted or modified, Vue associates state with the wrong elements
- It slows down the first render
What is available in the template of a
- Only exported variables
- Variables, functions and imports declared at the top level of the script
- Nothing without the data() method
The rest of the course
- Reactivity and the Composition API19 min
- Props, Events, v-model and Slots18 min
- Navigation with Vue Router18 min
- Shared State with Pinia and Testing19 min