TP Les formulaires Bootstrap 5.3 : portail d'inscription FormaPlus
-
Objectifs
- Ce TP de 6 heures clôt le chapitre Les formulaires Bootstrap. En le réalisant, vous allez apprendre à :
- intégrer Bootstrap 5.3 dans un site de plusieurs pages (CDN, gabarit commun, barre de navigation) ;
- utiliser tous les contrôles de formulaire: types
<input>HTML5,<textarea>,<select>,<datalist>,type="color",type="file"et curseur.form-range; - gérer les choix avec les cases à cocher, les boutons radio, les interrupteurs (
.form-switch) et les boutons bascules (.btn-check) ; - construire un formulaire de base (vertical) :
.form-label,.form-text, tailles,<fieldset>, champsreadonly/disabled; - construire des formulaires en ligne sans
.form-inline: grille.row-cols-lg-auto,.col-auto, utilitaires flex ; - construire un formulaire horizontal avec la grille :
.col-form-label,.offset-*,<legend>; - enrichir les champs avec les groupes de saisie (
.input-group) et les étiquettes flottantes (.form-floating) ; - mettre en place la validation côté navigateur (
novalidate,.was-validated, messages) et afficher une validation côté serveur (.is-valid/.is-invalid) ; - versionner son travail avec Git, le publier sur GitHub dès le départ et le mettre en ligne avec GitHub Pages: dépôt, commit à chaque étape, push,
README.mdet version finale étiquetée.
- Prérequis : HTML5 et CSS de base ; avoir lu les cours Contrôles de formulaire, Formulaires de base, Formulaires en ligne, Formulaires horizontaux et Validation des formulaires ; connaître le système de grille de Bootstrap (
.container,.row,.col-*). - Outils : un éditeur de code (VS Code conseillé, avec l'extension Live Server), un navigateur récent (Chrome, Firefox ou Edge) et ses outils de développement (F12).
- Avant la séance : un compte GitHub gratuit et Git installé sur le poste (vérifier avec
git --version).
-
Description
- Le centre de formation FormaPlus souhaite un petit site web pour présenter ses formations et permettre aux candidats de s'inscrire en ligne, de se connecter, de compléter leur profil et de contacter le centre.
- Le site final comporte cinq pages qui partagent la même barre de navigation. Chaque page met en œuvre un ou plusieurs types de formulaires Bootstrap :
| Page | Fichier | Type de formulaire et notions du chapitre |
|---|---|---|
| Accueil | index.html |
Formulaires en ligne: recherche dans la navbar, barre de filtres, newsletter |
| Inscription | inscription.html |
Formulaire de base (vertical) : tous les contrôles, cases, radios, interrupteurs, <fieldset>, validation |
| Connexion | connexion.html |
Étiquettes flottantes, groupes de saisie, afficher / masquer le mot de passe |
| Mon profil | profil.html |
Formulaire horizontal, validation côté serveur simulée (.is-valid / .is-invalid) |
| Contact | contact.html |
Validation complète : novalidate, JavaScript, messages, info-bulles |
- Répartition du temps :
| Partie | Notion(s) travaillée(s) | Durée |
|---|---|---|
| Partie 00 – Mise en place du projet et du dépôt GitHub | Git, GitHub, arborescence | 20 min |
| Partie 01 – Gabarit Bootstrap 5.3 et navigation | CDN, navbar, grille |
25 min |
| Partie 02 – Les contrôles de formulaire | .form-control, .form-select, .form-range, <datalist> |
45 min |
| Partie 03 – Cases, radios, interrupteurs et boutons bascules | .form-check, .form-switch, .btn-check |
40 min |
| Partie 04 – Le formulaire de base (vertical) | .form-label, .form-text, tailles, <fieldset>, readonly |
40 min |
| Partie 05 – Les formulaires en ligne | .row-cols-lg-auto, .col-auto, .d-flex, .visually-hidden |
35 min |
| Partie 06 – Le formulaire horizontal | .col-form-label, .offset-*, <legend> |
40 min |
| Partie 07 – Groupes de saisie et étiquettes flottantes | .input-group, .form-floating |
35 min |
| Partie 08 – La validation des formulaires | novalidate, .was-validated, .is-invalid, JavaScript |
50 min |
| Partie 09 – Intégration finale, GitHub Pages et version 1.0 | mode sombre, README.md, GitHub Pages, git tag |
30 min |
| Total | 6 h |
-
Travail à réaliser
-
Partie 00Mise en place du projet et du dépôt GitHub
- Q0.1. Créer un dossier
formapluset l'ouvrir dans VS Code (Fichier → Ouvrir le dossier). - Q0.2. Créer l'arborescence ci-dessous (à gauche). Les fichiers HTML peuvent être vides pour l'instant.
- Q0.3. Placer dans
images/deux images de votre choix : un logo (logo.png, environ 40 × 40 px) et une photo de profil (avatar.png, environ 150 × 150 px). Utilisez des images libres de droits ou créez-les vous-même. - Q0.4. Créer le fichier
.gitignore(à droite) pour exclure les fichiers propres à votre poste. - Q0.5. Créer le fichier
reponses.mdavec un titre# Réponses – TP Formulaires Bootstrapet votre nom : vous y noterez les réponses aux questions tout au long du TP.
formaplus/
├── .gitignore
├── README.md (Partie 09)
├── reponses.md (au fil du TP)
├── index.html (Accueil)
├── inscription.html (Inscription)
├── connexion.html (Connexion)
├── profil.html (Mon profil)
├── contact.html (Contact)
├── css/
│ └── style.css
├── js/
│ ├── main.js (Parties 02, 07, 09)
│ └── validation.js (Partie 08)
├── images/
│ ├── logo.png
│ └── avatar.png
└── captures/ (Partie 09)
# .gitignore
# Fichiers système
.DS_Store
Thumbs.db
# Paramètres de l'éditeur
.vscode/
# Fichiers temporaires
*.tmp
*.log
-
Publier le projet sur GitHub dès le départ
- Q0.6. Sur github.com/new, créer un dépôt public nommé
formaplus, sans cocher « Add a README », « .gitignore » ni « license » (le projet existe déjà en local). Le dépôt doit être public pour pouvoir utiliser GitHub Pages gratuitement en partie 09. - Q0.7. Configurer Git une seule fois sur le poste avec votre nom et l'adresse e-mail de votre compte GitHub (commandes 1 et 2 ci-dessous).
- Q0.8. Dans le dossier
formaplus, initialiser le dépôt local, faire le premier commit et l'envoyer sur GitHub (commandes 3 à 8). RemplacerVOTRE-COMPTEpar votre nom d'utilisateur GitHub.
# 1-2. Identité (une seule fois par poste)
git config --global user.name "Prénom Nom"
git config --global user.email "adresse@exemple.com"
# 3-8. Premier envoi du projet
cd formaplus
git init
git add .
git commit -m "Partie 00 : création du projet FormaPlus"
git branch -M main
git remote add origin https://github.com/VOTRE-COMPTE/formaplus.git
git push -u origin main
# Vérifications utiles
git status # fichiers modifiés
git log --oneline # historique des commits
git remote -v # adresse du dépôt GitHub
- Q0.9. Actualiser la page du dépôt sur GitHub. Le dossier
captures/est vide : apparaît-il sur GitHub ? Pourquoi ? Ajouter un fichier videcaptures/.gitkeep, puis faire un nouveau commit et un push. (Réponse dansreponses.md. ) - Q0.10. Envoyer le lien du dépôt à l'enseignant avant de commencer la partie 01.
Authentification : lors du premier
git push, GitHub n'accepte plus le mot de passe du compte. Connectez-vous par le navigateur quand Git le propose (Git Credential Manager, VS Code ou GitHub Desktop), ou utilisez un Personal Access Token (Settings → Developer settings → Personal access tokens) à la place du mot de passe.Règle du TP : un commit et un push à la fin de chaque partie.
Chaque partie se termine par un encadré « Git » qui donne le message de commit attendu. L'historique des commits fait partie de la note : un dépôt qui ne contient qu'un seul commit déposé en fin de séance n'obtient aucun point sur le critère Git.
Question de réflexion : pourquoi est-il préférable de faire plusieurs petits commits plutôt qu'un seul gros commit à la fin ?
Chaque partie se termine par un encadré « Git » qui donne le message de commit attendu. L'historique des commits fait partie de la note : un dépôt qui ne contient qu'un seul commit déposé en fin de séance n'obtient aucun point sur le critère Git.
Question de réflexion : pourquoi est-il préférable de faire plusieurs petits commits plutôt qu'un seul gros commit à la fin ?
-
Partie 01Gabarit Bootstrap 5.3 et navigation
- Objectif : créer une page modèle qui charge Bootstrap 5.3, puis la dupliquer pour obtenir les cinq pages du site.
- Q1.1. Dans
index.html, écrire le gabarit ci-dessous. Il charge la feuille de style de Bootstrap 5.3 et les icônes Bootstrap Icons dans le<head>, et le JavaScript de Bootstrap (bootstrap.bundle.min.js) juste avant</body>. - Q1.2. À quoi sert la balise
<meta name="viewport">? Supprimez-la temporairement et observez la page en mode mobile dans les outils de développement (F12 puis Ctrl+Maj+M). Remettez-la. - Q1.3. Pourquoi charge-t-on
bootstrap.bundle.min.jset nonbootstrap.min.js? (Indice : Popper. )
<!DOCTYPE html>
<html lang="fr" data-bs-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FormaPlus – Accueil</title>
<!-- Bootstrap 5.3 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<!-- Styles personnels (toujours APRÈS Bootstrap) -->
<link rel="stylesheet" href="css/style.css">
</head>
<body class="d-flex flex-column min-vh-100">
<!-- Barre de navigation (Q1.4) -->
<main class="container my-4 flex-grow-1">
<h1 class="h3 mb-4">Bienvenue sur FormaPlus</h1>
<!-- Contenu de la page -->
</main>
<footer class="bg-body-tertiary py-3 mt-auto">
<div class="container text-center small">© 2026 FormaPlus – Prénom Nom</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
- Q1.4. Ajouter une barre de navigation
.navbar.navbar-expand-lgsur fond sombre (.bg-dark+data-bs-theme="dark") contenant :- à gauche, la marque (
.navbar-brand) : le logoimages/logo.png(hauteur 32 px) suivi du texte « FormaPlus » ; - un bouton
.navbar-togglerqui replie le menu sur mobile (data-bs-toggle="collapse") ; - les liens : Accueil, Inscription, Connexion, Mon profil, Contact. Le lien de la page courante porte la classe
.activeet l'attributaria-current="page".
- à gauche, la marque (
- Q1.5. Réduire la largeur de la fenêtre : à partir de quelle largeur le menu se replie-t-il ? Quel mot de la classe
.navbar-expand-lgfixe ce seuil ? - Q1.6. Dupliquer
index.htmlpour créer les quatre autres pages. Pour chacune, adapter le<title>, le titre<h1>et le lien.active. Vérifier que la navigation fonctionne entre les cinq pages (avec Live Server). - Q1.7. Dans
css/style.css, ajouter une règle qui limite la largeur des formulaires à 900 px et les centre :
/* css/style.css */
.form-page {
max-width: 900px;
margin-inline: auto;
}
// js/main.js
// Ce fichier sera complété aux parties 02, 07 et 09.
console.log('FormaPlus : main.js chargé');
- Q1.8. Ouvrir la console du navigateur (F12 → Console) : le message de
main.jss'affiche-t-il ? S'il y a une erreur 404, corriger le chemin du fichier.

Résultat attendu à la fin de la partie 01.
Git – fin de la partie 01 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 01 : gabarit Bootstrap 5.3 et navigation des 5 pages"
git push
-
Partie 02Les contrôles de formulaire
- Objectif : construire la première version du formulaire d'inscription en utilisant tous les types de contrôles pris en charge par Bootstrap 5.3.
- Q2.1. Dans
inscription.html, à l'intérieur du<main>, créer le formulaire suivant. Chaque couple étiquette / champ est placé dans un<div class="mb-3">.
<form id="formInscription" class="form-page" action="#" method="get">
<h2 class="h5 mb-3"><i class="bi bi-person-vcard"></i> Informations personnelles</h2>
<div class="mb-3">
<label for="nom" class="form-label">Nom</label>
<input type="text" class="form-control" id="nom" name="nom" placeholder="Votre nom">
</div>
<!-- Q2.2 : compléter avec les autres champs -->
<button type="submit" class="btn btn-primary">Envoyer</button>
</form>
- Q2.2. Compléter la section « Informations personnelles » avec les champs suivants (chacun avec un
<label>, unidunique et un attributname). Choisir à chaque fois le bon type d'<input>:
| Champ | id / name |
Type à utiliser | Contraintes / remarques |
|---|---|---|---|
| Prénom | prenom |
… | placeholder « Votre prénom » |
| Adresse e-mail | email |
… | placeholder « nom@exemple.com » |
| Mot de passe | mdp |
… | — |
| Téléphone | tel |
… | placeholder « 20 123 456 » |
| Date de naissance | naissance |
… | — |
| Âge | age |
… | min="16", max="60" |
| Site web ou profil LinkedIn | site |
… | facultatif |
| Heure de disponibilité pour un appel | heure |
… | — |
- Q2.3. Ouvrir la page sur un téléphone (ou en mode mobile dans le navigateur). Comparer le clavier affiché pour les champs
email,teletnumber. Pourquoi le choix du type est-il important ? Remplir le tableau de la Q2.2 dansreponses.md. - Q2.4. Ajouter une deuxième section « Formation souhaitée » (titre
<h2 class="h5">avec l'icônebi-mortarboard) contenant :- une liste déroulante
<select class="form-select">« Domaine » : Développement web, Développement mobile, Réseaux, Bureautique. La première option « Choisir un domaine » porteselected disabled value=""; - une liste à sélection multiple « Langages déjà pratiqués » (
multiple,size="4") : HTML, CSS, JavaScript, PHP, Dart, Python ; - une zone de texte
<textarea>« Motivation » de 4 lignes.
- une liste déroulante
- Q2.5. Pourquoi utilise-t-on
.form-selectet non.form-controlsur un<select>en Bootstrap 5 ? Que se passe-t-il visuellement si vous utilisez.form-control? - Q2.6. Ajouter un champ « Ville » avec une liste de suggestions
<datalist>(Tunis, Nabeul, Sousse, Sfax, Bizerte, Monastir). Quelle est la différence entre un<datalist>et un<select>? - Q2.7. Ajouter un champ « Couleur préférée pour votre badge » de type
color. Quelles deux classes faut-il lui donner ? - Q2.8. Ajouter un champ « CV (PDF) » de type
fileavec la classe.form-controlet l'attributaccept=".pdf". Que change l'attributacceptdans la fenêtre de choix de fichier ? - Q2.9. Ajouter un curseur « Niveau en informatique » (
type="range", classe.form-range, de 0 à 10, pas de 1, valeur initiale 5). À côté de l'étiquette, afficher la valeur courante dans un<span id="niveauValeur" class="badge text-bg-primary">5</span>, mise à jour par le script suivant (à placer dansjs/main.js) :
<div class="mb-3">
<label for="niveau" class="form-label">
Niveau en informatique :
<span id="niveauValeur" class="badge text-bg-primary">5</span>
</label>
<input type="range" class="form-range" id="niveau"
name="niveau" min="0" max="10" step="1" value="5">
</div>
// js/main.js – Q2.9 : afficher la valeur du curseur
const niveau = document.getElementById('niveau');
const niveauValeur = document.getElementById('niveauValeur');
if (niveau && niveauValeur) { // le curseur n'existe que sur inscription.html
niveau.addEventListener('input', () => {
niveauValeur.textContent = niveau.value;
});
}
- Q2.10. Pourquoi le script teste-t-il
if (niveau && niveauValeur)avant d'ajouter l'écouteur ? (Indice :main.jsest chargé sur les cinq pages.) - Q2.11 (approfondissement). Ajouter les classes
.form-control-lgsur le champ e-mail et.form-select-smsur la liste « Domaine ». Comparer, puis retirer ces classes.

Résultat attendu à la fin de la partie 02 (extrait).
Question de réflexion :
Bootstrap ne crée pas de nouveaux contrôles : il met en forme les contrôles HTML5 existants. Citez trois avantages d'utiliser les types HTML5 natifs plutôt que des champs
Bootstrap ne crée pas de nouveaux contrôles : il met en forme les contrôles HTML5 existants. Citez trois avantages d'utiliser les types HTML5 natifs plutôt que des champs
type="text" partout.Git – fin de la partie 02 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 02 : contrôles de formulaire de la page Inscription"
git push
-
Partie 03Cases à cocher, boutons radio, interrupteurs et boutons bascules
- Objectif : permettre au candidat de faire des choix simples ou multiples, avec les différentes présentations proposées par Bootstrap 5.3.
- Q3.1. Dans
inscription.html, ajouter une troisième section « Préférences » (icônebi-sliders). Y placer un groupe de cases à cocher « Centres d'intérêt » : Sites web, Applications mobiles, Jeux vidéo, Intelligence artificielle, Cybersécurité. Respecter la structure :
<p class="form-label">Centres d'intérêt</p>
<div class="form-check">
<input class="form-check-input" type="checkbox"
id="interetWeb" name="interets" value="web">
<label class="form-check-label" for="interetWeb">Sites web</label>
</div>
<!-- … les 4 autres cases -->
.form-check: le conteneur ;.form-check-input: la case ;.form-check-label: son étiquette ;- chaque
idest unique; toutes les cases du groupe partagent le mêmename.
- Q3.2. Cocher par défaut « Sites web » (
checked) et désactiver « Jeux vidéo » (disabled) avec la mention « (bientôt disponible) ». Pourquoi l'étiquette de la case désactivée apparaît-elle aussi grisée ? - Q3.3. Ajouter un groupe de boutons radio « Niveau d'études » : Baccalauréat, BTP, BTS, Licence, Autre. Les afficher sur une seule ligne avec
.form-check-inline. « Baccalauréat » est sélectionné par défaut. - Q3.4. Donner volontairement un
namedifférent à l'un des boutons radio, puis tester. Que constatez-vous ? Corriger et expliquer dansreponses.mdle rôle de l'attributnamepour les boutons radio. - Q3.5. Ajouter deux interrupteurs (
.form-check.form-switch, avecrole="switch") : « Recevoir la newsletter » (activé) et « Recevoir les SMS de rappel » (désactivé). Un interrupteur est-il une case à cocher ou un bouton radio ? Justifier à partir du code. - Q3.6. Ajouter le choix « Séance préférée » sous forme de boutons radio bascules: Matin, Après-midi, Soir, Samedi. Utiliser un
.btn-group, la classe.btn-checksur chaque<input type="radio">et.btn.btn-outline-primarysur chaque<label>:
<p class="form-label">Séance préférée</p>
<div class="btn-group mb-3" role="group" aria-label="Séance préférée">
<input type="radio" class="btn-check" name="seance" id="seanceMatin" value="matin" autocomplete="off" checked>
<label class="btn btn-outline-primary" for="seanceMatin"><i class="bi bi-sunrise"></i> Matin</label>
<input type="radio" class="btn-check" name="seance" id="seanceAprem" value="apres-midi" autocomplete="off">
<label class="btn btn-outline-primary" for="seanceAprem"><i class="bi bi-sun"></i> Après-midi</label>
<!-- Q3.6 : compléter avec Soir (bi-moon) et Samedi (bi-calendar-week) -->
</div>
- Q3.7. Ajouter un groupe de cases bascules « Modalités acceptées » : Présentiel, À distance, Hybride (
type="checkbox"+.btn-check, labels en.btn-outline-success). Plusieurs choix doivent être possibles en même temps : vérifier. - Q3.8. Terminer la section par une case obligatoire « J'accepte le règlement intérieur du centre » (elle sera validée en partie 08).
- Q3.9. Compléter le tableau suivant dans
reponses.md:
| Présentation | Type d'<input> |
Classe(s) Bootstrap | Nombre de choix possibles | Exemple d'usage |
|---|---|---|---|---|
| Case à cocher | … | … | … | … |
| Bouton radio | … | … | … | … |
| Interrupteur | … | … | … | … |
| Bouton bascule | … | … | … | … |

Résultat attendu à la fin de la partie 03 : section « Préférences ».
Git – fin de la partie 03 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 03 : cases, radios, interrupteurs et boutons bascules"
git push
-
Partie 04Le formulaire de base (vertical)
- Objectif : finaliser la mise en forme du formulaire d'inscription : textes d'aide, disposition en colonnes, regroupements, champs en lecture seule et observation des données envoyées.
- Q4.1. Sous le champ « Mot de passe », ajouter un texte d'aide
.form-text: « 8 à 20 caractères, avec au moins un chiffre. » Le relier au champ avecaria-describedby. À quoi sert cet attribut pour un utilisateur malvoyant ? - Q4.2. Ajouter de la même façon un texte d'aide sous l'e-mail (« Nous ne partagerons jamais votre adresse. ») et sous le CV (« Format PDF, 2 Mo maximum. »).
- Q4.3. Disposer les champs sur deux colonnes sur les écrans moyens et grands, et sur une colonne sur mobile :
- la section « Informations personnelles » devient un
<div class="row g-3">; - chaque champ est placé dans un
<div class="col-md-6">(Nom / Prénom, E-mail / Téléphone, etc.) ; - la classe
.mb-3devient inutile à l'intérieur de la ligne : pourquoi ? (Indice :.g-3. )
- la section « Informations personnelles » devient un
<div class="row g-3 mb-4">
<div class="col-md-6">
<label for="nom" class="form-label">Nom</label>
<input type="text" class="form-control" id="nom" name="nom" placeholder="Votre nom">
</div>
<div class="col-md-6">
<label for="prenom" class="form-label">Prénom</label>
<input type="text" class="form-control" id="prenom" name="prenom" placeholder="Votre prénom">
</div>
<div class="col-md-6">
<label for="mdp" class="form-label">Mot de passe</label>
<input type="password" class="form-control" id="mdp" name="mdp" aria-describedby="mdpAide">
<div id="mdpAide" class="form-text">8 à 20 caractères, avec au moins un chiffre.</div>
</div>
<!-- … -->
<div class="col-12">
<!-- un champ sur toute la largeur, ex. Motivation -->
</div>
</div>
- Q4.4. Placer chacune des trois sections dans une carte (
.card>.card-header+.card-body) séparées par.mb-4. Le titre<h2>de chaque section passe dans le.card-header. - Q4.5. Ajouter en fin de formulaire une quatrième carte « Réservé à l'administration » contenant un
<fieldset disabled>avec une<legend class="fs-6">et deux champs : « Numéro de dossier » et « Décision » (liste : En attente, Accepté, Refusé). Que fait l'attributdisabledplacé sur le<fieldset>? - Q4.6. Dans la carte « Informations personnelles », ajouter en tête un champ « Session » avec la valeur
Session d'octobre 2026:- d'abord avec l'attribut
readonly; - puis avec la classe
.form-control-plaintext(à la place de.form-control) etreadonly. Quelle différence visuelle observez-vous ? Garder la seconde version.
- d'abord avec l'attribut
- Q4.7. En bas du formulaire, placer deux boutons : « Envoyer ma candidature » (
type="submit",.btn-primary.btn-lg) et « Effacer » (type="reset",.btn-outline-secondary.btn-lg), séparés par.me-2. Sur mobile, ils doivent occuper toute la largeur : utiliser<div class="d-grid gap-2 d-md-block">. -
Observer les données envoyées
- Q4.8. Le formulaire utilise
method="get": remplir quelques champs, cliquer sur « Envoyer » et observer la barre d'adresse. Copier l'URL obtenue dansreponses.md. - Q4.9. À partir de cette URL, répondre :
- un champ sans attribut
nameest-il envoyé ? (Supprimer temporairement lenamedu prénom pour vérifier.) - le champ « Session » (
readonly) est-il envoyé ? Et les champs du<fieldset disabled>? - comment apparaissent plusieurs cases « Centres d'intérêt » cochées ? Une case non cochée est-elle envoyée ?
- pourquoi ne faut-il jamais utiliser
method="get"pour un formulaire qui contient un mot de passe ?
- un champ sans attribut
- Q4.10. Remplacer
method="get"parmethod="post". Le formulaire est-il toujours visible dans l'URL ? Où peut-on voir les données envoyées dans les outils de développement (onglet Réseau / Network) ?

Résultat attendu à la fin de la partie 04 : version grand écran (à gauche) et mobile (à droite).
Question de réflexion :
Quelle est la différence entre
Quelle est la différence entre
readonly et disabled du point de vue de l'utilisateur et du point de vue des données envoyées ? Donnez un exemple d'usage pour chacun.Git – fin de la partie 04 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 04 : formulaire d'inscription vertical, cartes et fieldset"
git push
-
Partie 05Les formulaires en ligne
- Objectif : créer sur la page d'accueil trois petits formulaires dont tous les éléments sont alignés sur une ligne, sans la classe
.form-inline(supprimée en Bootstrap 5). -
Formulaire 1 : recherche dans la barre de navigation
- Q5.1. Dans la
navbarde toutes les pages, après la liste des liens, ajouter un formulaire de recherche :
<form class="d-flex" role="search" action="index.html" method="get">
<input class="form-control me-2" type="search" name="q"
placeholder="Rechercher une formation" aria-label="Rechercher une formation">
<button class="btn btn-outline-light" type="submit"><i class="bi bi-search"></i></button>
</form>
- Q5.2. Ce formulaire n'a pas de
<label>: qu'est-ce qui le remplace pour l'accessibilité ? Le bouton ne contient qu'une icône : ajouter un texte<span class="visually-hidden">Rechercher</span>dans le bouton. Pourquoi ? - Q5.3. Pour que la recherche soit poussée à droite du menu, ajouter
.me-autoà la liste.navbar-nav. Expliquer le fonctionnement de.me-autodans un conteneur flex. -
Formulaire 2 : barre de filtres des formations
- Q5.4. Dans
index.html, sous le titre, ajouter une section « Nos formations » avec un formulaire de filtres utilisant la grille (méthode recommandée par Bootstrap) :<form class="row row-cols-lg-auto g-3 align-items-center mb-4">;- chaque élément dans un
<div class="col-12">; - une liste « Domaine », une liste « Niveau » (Débutant, Intermédiaire, Avancé), une case à cocher « Certifiante uniquement » et un bouton « Filtrer » ;
- les étiquettes des listes sont masquées avec
.visually-hidden.
- Q5.5. Passer en mode mobile (Ctrl+Maj+M) : comment se comporte la barre de filtres ? Remplacer
.row-cols-lg-autopar.row-cols-md-auto: à partir de quelle largeur les éléments passent-ils maintenant en ligne ? - Q5.6. Sous la barre de filtres, afficher trois formations sous forme de cartes (
.row.row-cols-1.row-cols-md-3.g-4) : titre, durée, niveau (.badge) et un bouton « S'inscrire » qui mène versinscription.html. Ajouter une image en haut de chaque carte (.card-img-top, images de votre choix dansimages/). -
Formulaire 3 : inscription à la newsletter
- Q5.7. Avant le pied de page, ajouter un bandeau
.bg-primary-subtle.rounded.p-4contenant un formulaire en ligne basé sur.col-auto:
<form class="row g-2 align-items-center justify-content-center">
<div class="col-auto">
<label for="newsletterEmail" class="col-form-label fw-semibold">Restez informé :</label>
</div>
<div class="col-12 col-sm">
<input type="email" class="form-control" id="newsletterEmail" name="email" placeholder="Votre e-mail">
</div>
<div class="col-auto">
<!-- Q5.7 : bouton « S'abonner » -->
</div>
</form>
- Q5.8. Expliquer la différence entre
.col-auto,.colet.col-12dans cet exemple. - Q5.9. Réécrire la barre de filtres de la Q5.4 avec les utilitaires flex (
.d-flex.flex-wrap.align-items-center.gap-2) au lieu de la grille. Les listes doivent avoir.w-auto. Garder la version de votre choix et justifier ce choix dansreponses.md. - Q5.10. Compléter dans
reponses.md: « En Bootstrap 4, on écrivait<form class="form-inline">et.visually-hidden. En Bootstrap 5.3, on écrit … »

Résultat attendu à la fin de la partie 05 : page d'accueil.
Git – fin de la partie 05 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 05 : formulaires en ligne – recherche, filtres et newsletter"
git push
-
Partie 06Le formulaire horizontal
- Objectif : construire la page « Mon profil » avec une disposition horizontale : étiquette à gauche, champ à droite, une ligne par champ.
- Q6.1. Dans
profil.html, créer une mise en page en deux colonnes (.row) : à gauche (.col-lg-3) une carte avec la photoimages/avatar.png(classes.img-thumbnail.rounded-circle), le nom du candidat et un champ fichier « Changer de photo » (accept="image/*",.form-control-sm) ; à droite (.col-lg-9) le formulaire horizontal. - Q6.2. Créer les lignes « Nom », « Prénom » et « E-mail » selon la structure horizontale. Vérifier que la somme des colonnes vaut 12 sur chaque ligne :
<form id="formProfil" action="#" method="post">
<div class="row mb-3">
<label for="profilNom" class="col-sm-3 col-form-label">Nom</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="profilNom" name="nom" value="Ben Salah">
</div>
</div>
<!-- Q6.2 : Prénom, E-mail -->
</form>
- Q6.3. Ajouter une ligne « Identifiant » affichée en texte simple (
.form-control-plaintext+readonly, valeurFP-2026-0142). - Q6.4. Ajouter une ligne « Genre » sous forme de boutons radio en ligne, avec la structure
<fieldset class="row mb-3">+<legend class="col-form-label col-sm-3 pt-0">. Retirer puis remettre.pt-0: quel est son rôle ? - Q6.5. Ajouter une ligne « Adresse » (toute la largeur), puis une ligne qui contient deux champs: « Code postal » (
.col-sm-3) et « Ville » (avec sa propre étiquette.col-sm-2et un champ.col-sm-4). Le total de la ligne fait-il 12 ? Corriger si nécessaire. - Q6.6. Ajouter une ligne « Biographie » avec un
<textarea>de 3 lignes et un texte d'aide.form-text(« 200 caractères maximum », attributmaxlength="200"). - Q6.7. Ajouter une ligne sans étiquette contenant l'interrupteur « Profil visible par les formateurs ». Utiliser
.offset-sm-3pour l'aligner avec les champs. - Q6.8. Ajouter une section « Paramètres d'affichage » utilisant les étiquettes de taille différente :
- une ligne « Langue » en petit format :
.col-form-label-sm+.form-select-sm; - une ligne « Pseudo » en grand format :
.col-form-label-lg+.form-control-lg. - Que se passe-t-il si on oublie
.col-form-label-lgsur l'étiquette du grand champ ?
- une ligne « Langue » en petit format :
- Q6.9. Terminer par les boutons « Enregistrer » et « Annuler » alignés avec les champs (
.offset-sm-3). - Q6.10. Rendre la disposition plus fine selon la taille de l'écran : les étiquettes occupent
.col-md-4.col-lg-3et les champs.col-md-8.col-lg-9. Tester les trois tailles (mobile, tablette, ordinateur) et décrire le comportement dansreponses.md.

Résultat attendu à la fin de la partie 06 : page « Mon profil ».
Question de réflexion :
Le code d'origine de nombreux tutoriels utilise
Le code d'origine de nombreux tutoriels utilise
.form-horizontal, .form-group, .control-label et .col-sm-offset-2. À quelle version de Bootstrap appartiennent ces classes ? Par quoi les remplace-t-on en Bootstrap 5.3 ?Git – fin de la partie 06 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 06 : page Mon profil en formulaire horizontal"
git push
-
Partie 07Groupes de saisie et étiquettes flottantes
- Objectif : créer une page de connexion moderne avec les étiquettes flottantes, et enrichir des champs avec des icônes, du texte et des boutons accolés.
-
Étiquettes flottantes
- Q7.1. Dans
connexion.html, centrer une carte de connexion :<div class="row justify-content-center">><div class="col-sm-10 col-md-7 col-lg-5">>.card.shadow-sm. En haut de la carte, afficher le logo et le titre « Connexion ». - Q7.2. Dans la carte, créer les champs « Adresse e-mail » et « Mot de passe » avec des étiquettes flottantes:
<div class="form-floating mb-3">
<input type="email" class="form-control" id="connexionEmail"
name="email" placeholder="nom@exemple.com">
<label for="connexionEmail">Adresse e-mail</label>
</div>
- l'
<input>est placé avant le<label>; - l'attribut
placeholderest obligatoire, même s'il n'est pas affiché ; - le
<label>n'a pas de classe.
- Q7.3. Supprimer le
placeholderdu champ e-mail et observer le comportement de l'étiquette. Expliquer pourquoi Bootstrap en a besoin (indice : pseudo-classe CSS:placeholder-shown). Remettre leplaceholder. - Q7.4. Ajouter sous les champs : une case « Se souvenir de moi », un bouton « Se connecter » pleine largeur (
.w-100.btn-lg) et un lien « Pas encore de compte ? S'inscrire » versinscription.html. - Q7.5. Dans
contact.html, créer un premier jet du formulaire de contact entièrement en étiquettes flottantes : « Nom complet », « E-mail », « Objet » (<select class="form-select">: Renseignements, Inscription, Réclamation, Autre) et « Message » (<textarea>d'une hauteur de 150 px fixée parstyle="height: 150px"). Pourquoi l'attributrowsne suffit-il pas pour un<textarea>flottant ? - Q7.6. Placer « Nom complet » et « E-mail » côte à côte (
.row.g-2+.col-md), chaque colonne contenant son propre.form-floating. -
Groupes de saisie
- Q7.7. Dans
connexion.html, remplacer le champ mot de passe par un groupe de saisie qui combine une icône, l'étiquette flottante et un bouton « afficher / masquer » :
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<div class="form-floating">
<input type="password" class="form-control" id="connexionMdp"
name="mdp" placeholder="Mot de passe">
<label for="connexionMdp">Mot de passe</label>
</div>
<button class="btn btn-outline-secondary" type="button"
id="btnVoirMdp" aria-label="Afficher le mot de passe">
<i class="bi bi-eye"></i>
</button>
</div>
// js/main.js – Q7.8
const btnVoirMdp = document.getElementById('btnVoirMdp');
const champMdp = document.getElementById('connexionMdp');
if (btnVoirMdp && champMdp) {
btnVoirMdp.addEventListener('click', () => {
const masque = champMdp.type === 'password';
champMdp.type = masque ? 'text' : 'password';
btnVoirMdp.innerHTML = masque
? '<i class="bi bi-eye-slash"></i>'
: '<i class="bi bi-eye"></i>';
// Q7.8 : mettre aussi à jour aria-label
});
}
- Q7.8. Ajouter le script ci-dessus dans
js/main.jset le compléter pour que l'attributaria-labeldu bouton devienne « Masquer le mot de passe » quand le mot de passe est visible. Pourquoi le bouton a-t-iltype="button"et nontype="submit"? - Q7.9. Faire de même pour l'e-mail : icône
bi-envelopedans un.input-group-textà gauche de l'étiquette flottante. - Q7.10. Dans
inscription.html, transformer trois champs en groupes de saisie :- « Téléphone » : texte
+216à gauche ; - « Site web » : texte
https://à gauche ; - « Budget de formation » (nouveau champ
number) : texteDTà droite et.00en second suffixe.
- « Téléphone » : texte
- Q7.11. Sur la page d'accueil, refaire la newsletter de la Q5.7 avec un groupe de saisie (champ e-mail et bouton « S'abonner » accolés), en taille grande (
.input-group-lg). Quelle version préférez-vous ? Garder la meilleure. - Q7.12 (approfondissement). Ajouter à la barre de recherche de la
navbarun menu déroulant (.dropdown-toggledans le.input-group) permettant de choisir où chercher : « Formations », « Formateurs », « Actualités ». Quel fichier JavaScript de Bootstrap est nécessaire pour que le menu s'ouvre ?

Résultat attendu à la fin de la partie 07 : page de connexion.
Git – fin de la partie 07 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 07 : étiquettes flottantes et groupes de saisie"
git push
-
Partie 08La validation des formulaires
- Objectif : empêcher l'envoi de formulaires incomplets ou incorrects et guider l'utilisateur avec des messages clairs, côté navigateur, puis simuler l'affichage d'erreurs renvoyées par un serveur.
-
Déclarer les règles en HTML5
- Q8.1. Dans
contact.html, ajouter les règles suivantes au formulaire de contact de la partie 07, puis essayer de l'envoyer vide. Que fait le navigateur sans Bootstrap ?
| Champ | Règle(s) à ajouter | Message d'erreur à afficher (Q8.3) |
|---|---|---|
| Nom complet | required, minlength="3" |
Veuillez saisir votre nom (3 caractères minimum). |
required (le type email vérifie déjà le format) |
Veuillez saisir une adresse e-mail valide. | |
| Objet | required + première option value="" |
Veuillez choisir un objet. |
| Message | required, minlength="20", maxlength="500" |
Votre message doit contenir entre 20 et 500 caractères. |
| Case « J'accepte que mes données soient utilisées pour me répondre » | required |
Vous devez accepter avant d'envoyer. |
-
Afficher les messages Bootstrap
- Q8.2. Ajouter au
<form>l'attributnovalidateet la classe.needs-validation. Essayer à nouveau d'envoyer le formulaire vide : que se passe-t-il maintenant ? Pourquoi ? - Q8.3. Sous chaque champ, ajouter un
<div class="invalid-feedback">avec le message du tableau. Sous « Nom complet » et « E-mail », ajouter aussi un<div class="valid-feedback">Parfait !</div>. Pour la case à cocher, le message se place dans le.form-checkmais après le<label>. - Q8.4. Créer le fichier
js/validation.jsavec le script officiel de Bootstrap, l'inclure danscontact.html,inscription.htmletconnexion.html(aprèsbootstrap.bundle.min.js) :
// js/validation.js – validation Bootstrap 5.3 de tous les formulaires .needs-validation
(() => {
'use strict';
const forms = document.querySelectorAll('.needs-validation');
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault(); // bloque l'envoi
event.stopPropagation();
}
form.classList.add('was-validated'); // affiche les couleurs et les messages
}, false);
});
})();
- Q8.5. Tester : envoyer le formulaire vide, puis corriger les champs un par un. Les couleurs changent-elles pendant la saisie ? Expliquer le rôle de
checkValidity(), deevent.preventDefault()et de la classe.was-validated. - Q8.6. Retirer le script et placer directement
class="was-validated"sur le<form>. Recharger la page : quel problème d'ergonomie apparaît ? Remettre le script. - Q8.7. Pour « Objet », remplacer
.invalid-feedbackpar une info-bulle.invalid-tooltip. Que faut-il ajouter au parent pour qu'elle soit bien placée ? (Avec les étiquettes flottantes, le.form-floatingest déjà positionné : vérifier.) -
Valider le formulaire d'inscription
- Q8.8. Dans
inscription.html, ajouternovalidateet.needs-validationau formulaire, puis les règles et messages suivants :- Nom, Prénom, E-mail, Domaine, case « Règlement intérieur » :
required; - Mot de passe :
required,minlength="8",maxlength="20",pattern="(?=.*[0-9]).{8,20}"(au moins un chiffre) ; - Téléphone :
pattern="[0-9]{8}"(8 chiffres) ; - Âge :
min="16"etmax="60"(déjà présents) ; - CV :
required.
- Nom, Prénom, E-mail, Domaine, case « Règlement intérieur » :
- Q8.9. Le téléphone et le site web sont dans des groupes de saisie (Q7.10) : le message d'erreur s'affiche-t-il correctement ? Ajouter la classe
.has-validationau.input-groupet comparer les coins arrondis. - Q8.10. Ajouter un champ « Confirmer le mot de passe » (
id="mdp2"). HTML5 ne sait pas comparer deux champs : le faire en JavaScript avecsetCustomValidity(), puis afficher le message « Les deux mots de passe ne correspondent pas. » :
// js/validation.js – Q8.10 : confirmation du mot de passe
const mdp = document.getElementById('mdp');
const mdp2 = document.getElementById('mdp2');
function verifierConfirmation() {
if (mdp2.value !== mdp.value) {
mdp2.setCustomValidity('Les mots de passe ne correspondent pas.');
} else {
mdp2.setCustomValidity(''); // chaîne vide = champ valide
}
}
if (mdp && mdp2) {
mdp.addEventListener('input', verifierConfirmation);
mdp2.addEventListener('input', verifierConfirmation);
}
- tant que
setCustomValidity()reçoit un texte non vide, le champ est considéré comme:invalid; - pourquoi faut-il surveiller les deux champs et pas seulement
mdp2? - ajouter le
.invalid-feedbackcorrespondant dans le HTML.
- Q8.11. Le bouton « Effacer » (
type="reset") vide les champs mais les couleurs restent affichées. Ajouter dansvalidation.jsun écouteur sur l'événementresetdu formulaire qui retire la classe.was-validated. -
Simuler un envoi réussi
- Q8.12. Pour le formulaire de contact, quand le formulaire est valide, bloquer quand même l'envoi (pas de serveur dans ce TP), afficher une alerte Bootstrap de succès au-dessus du formulaire, vider le formulaire et retirer
.was-validated:
<!-- contact.html, au-dessus du formulaire -->
<div id="alerteSucces" class="alert alert-success d-none" role="alert">
<i class="bi bi-check-circle"></i>
Merci ! Votre message a bien été envoyé.
</div>
// À compléter dans l'écouteur submit, si le formulaire est valide :
// 1. event.preventDefault();
// 2. afficher #alerteSucces (retirer la classe d-none) ;
// 3. form.reset();
// 4. form.classList.remove('was-validated');
// 5. masquer l'alerte au bout de 4 secondes (setTimeout).
-
Afficher une validation côté serveur
- Q8.13. Dans
profil.html, on imagine que le serveur a vérifié le formulaire et renvoie le résultat. Simuler cette réponse en HTML, sans JavaScript :- le champ E-mail porte
.is-invalidavec le message « Cette adresse est déjà utilisée par un autre compte. » ; - les champs Nom et Prénom portent
.is-valid; - chaque message est relié à son champ par
aria-describedby; - en haut du formulaire, une alerte
.alert-dangerrésume l'erreur.
- le champ E-mail porte
- Q8.14. Pourquoi les classes
.is-valid/.is-invalidn'ont-elles pas besoin d'un parent.was-validated? Dans quel langage (PHP, Symfony…) seraient-elles ajoutées dans un vrai projet ?

Résultat attendu à la fin de la partie 08 : formulaire de contact après une tentative d'envoi.
Questions de réflexion :
1) Un utilisateur peut désactiver JavaScript ou modifier le HTML avec F12 (par exemple supprimer l'attribut
2) Pourquoi la première option d'un
3) Donnez deux règles d'un bon message d'erreur.
1) Un utilisateur peut désactiver JavaScript ou modifier le HTML avec F12 (par exemple supprimer l'attribut
required). Que pouvez-vous en conclure sur la validation côté navigateur ?2) Pourquoi la première option d'un
<select required> doit-elle avoir value=""? 3) Donnez deux règles d'un bon message d'erreur.
Git – fin de la partie 08 : enregistrer et publier votre travail, puis vérifier le nouveau commit sur GitHub.
git add .
git commit -m "Partie 08 : validation des formulaires Contact, Inscription et Profil"
git push
-
Partie 09Intégration finale, GitHub Pages et version 1.0
- Objectif : harmoniser le site, ajouter le mode sombre de Bootstrap 5.3, le mettre en ligne et livrer une version finale propre.
-
Mode sombre
- Q9.1. Bootstrap 5.3 gère nativement un thème sombre avec l'attribut
data-bs-theme. Dans lanavbarde toutes les pages, ajouter un boutonid="btnTheme"(icônebi-moon-stars), puis compléterjs/main.js:
// js/main.js – Q9.1 : bascule clair / sombre mémorisée
const racine = document.documentElement; // la balise <html>
const btnTheme = document.getElementById('btnTheme');
let themeEnregistre = null;
try { themeEnregistre = localStorage.getItem('theme'); } catch (e) {}
if (themeEnregistre) {
racine.setAttribute('data-bs-theme', themeEnregistre);
}
if (btnTheme) {
btnTheme.addEventListener('click', () => {
const nouveau = racine.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark';
racine.setAttribute('data-bs-theme', nouveau);
try { localStorage.setItem('theme', nouveau); } catch (e) {}
// Q9.2 : changer l'icône (bi-moon-stars / bi-sun)
});
}
- Q9.2. Compléter le script pour que l'icône du bouton devienne
bi-sunen mode sombre. Changer de page : le thème est-il conservé ? Quel est le rôle delocalStorage? - Q9.3. Passer en mode sombre et parcourir les cinq pages. Les éléments qui utilisent des couleurs fixes (
.bg-light,.text-dark) restent-ils lisibles ? Les remplacer par les classes adaptatives de Bootstrap 5.3 :.bg-body-tertiary,.text-body,.bg-primary-subtle… -
Vérifications finales
- Q9.4. Pour chaque page, vérifier avec la liste de contrôle suivante et corriger si nécessaire :
- le lien de la page courante est
.activedans lanavbar; - chaque champ a une étiquette (visible,
.visually-hiddenouaria-label) reliée parfor/id; - aucun
idn'est utilisé deux fois sur une même page ; - chaque image a un attribut
altdescriptif ; - la console du navigateur ne contient aucune erreur.
- le lien de la page courante est
- Q9.5. Valider le code HTML de chaque page avec le validateur du W3C (validator.w3.org, onglet Validate by Direct Input). Noter dans
reponses.mdle nombre d'erreurs trouvées et corrigées. - Q9.6. Lancer un audit Lighthouse (F12 → onglet Lighthouse → catégorie Accessibility) sur
inscription.html. Noter le score et corriger au moins deux problèmes signalés. - Q9.7. Faire une capture d'écran de chaque page (version ordinateur) et des pages Inscription et Contact en version mobile, puis du formulaire de contact en mode sombre. Les enregistrer au format PNG dans
captures/:accueil.png,inscription.png,inscription-mobile.png,connexion.png,profil.png,contact.png,contact-mobile.png,contact-sombre.png. -
Mettre le site en ligne avec GitHub Pages
- Q9.8. Faire un commit et un push de toutes les modifications. Sur GitHub, ouvrir le dépôt, puis Settings → Pages: dans Build and deployment, choisir Source : Deploy from a branch, Branch : main, dossier / (root), puis Save.
- Q9.9. Après une à deux minutes, le site est disponible à l'adresse
https://VOTRE-COMPTE.github.io/formaplus/. Ouvrir cette adresse sur votre téléphone et tester les cinq pages. Pourquoi la page d'accueil doit-elle obligatoirement s'appelerindex.html? -
Finaliser le dépôt GitHub
- Q9.10. Créer à la racine du projet un fichier
README.mdqui présente le site (modèle ci-dessous) : description, lien vers le site en ligne, pages et notions, captures d'écran et auteur. - Q9.11. Vérifier que
reponses.mdest complet et présent à la racine du dépôt. - Q9.12. Faire le dernier commit, puis marquer la version finale avec une étiquette
v1.0et l'envoyer sur GitHub (commandes ci-dessous). Vérifier sur GitHub que le README s'affiche avec les captures et que l'étiquette apparaît dans Tags.
# FormaPlus
Site web d'un centre de formation réalisé dans le cadre
du TP « Les formulaires Bootstrap 5.3 ».
**Site en ligne :** https://VOTRE-COMPTE.github.io/formaplus/
## Pages et notions
| Page | Type de formulaire |
|------|--------------------|
| Accueil | Formulaires en ligne (recherche, filtres, newsletter) |
| Inscription | Formulaire de base, tous les contrôles, validation |
| Connexion | Étiquettes flottantes, groupes de saisie |
| Mon profil | Formulaire horizontal, validation serveur simulée |
| Contact | Validation complète avec JavaScript |
## Technologies
- HTML5, CSS3, JavaScript
- Bootstrap 5.3 et Bootstrap Icons
## Captures d'écran



## Auteur
Prénom Nom – Groupe
git add .
git commit -m "Partie 09 : mode sombre, README, captures et mise en ligne"
git push
git tag v1.0
git push origin v1.0

Résultat attendu à la fin de la partie 09 : le site publié sur GitHub Pages, en mode sombre.
-
Exercices complémentaires (bonus)
- Indicateur de force du mot de passe : sous le mot de passe de l'inscription, afficher une barre de progression Bootstrap (
.progress) qui passe du rouge au vert selon la longueur et la présence de chiffres, majuscules et caractères spéciaux. - Compteur de caractères : sous le message du formulaire de contact, afficher « 120 / 500 caractères » mis à jour en temps réel.
- Formulaire en plusieurs étapes : découper l'inscription en trois étapes avec les onglets Bootstrap (
.nav-pills) et des boutons « Suivant » / « Précédent », en validant chaque étape avant de passer à la suivante. - Récapitulatif dans une fenêtre modale : avant l'envoi de l'inscription, afficher les données saisies dans une
.modalBootstrap avec les boutons « Modifier » et « Confirmer ». - Intégration continue : ajouter un fichier
.github/workflows/html.ymlqui vérifie le HTML à chaquegit push(GitHub Actions, par exemple avechtml-validate), et afficher le badge de statut dans leREADME.md.
-
Compte rendu
- À rendre :
- le lien de votre dépôt GitHub
formaplus, envoyé dès la partie 00 : c'est ce dépôt qui est corrigé, dans l'état de l'étiquettev1.0; - le lien du site en ligne sur GitHub Pages (
https://VOTRE-COMPTE.github.io/formaplus/) ; - dans le dépôt, le fichier
reponses.md: réponses aux questions Q0.9, Q1.2, Q1.3, Q1.5, Q2.3, Q2.5, Q2.6, Q2.10, Q3.2, Q3.4, Q3.5, Q4.1, Q4.3, Q4.5, Q4.8, Q4.9, Q4.10, Q5.2, Q5.3, Q5.5, Q5.8, Q5.9, Q5.10, Q6.4, Q6.8, Q6.10, Q7.3, Q7.5, Q7.8, Q7.11, Q8.1, Q8.2, Q8.5, Q8.6, Q8.14, Q9.2, Q9.5, Q9.6, Q9.9, aux questions de réflexion et les tableaux des Q2.2 et Q3.9 ; - dans le dépôt, le
README.mdet les captures d'écran du dossiercaptures/.
- le lien de votre dépôt GitHub
- Barème indicatif (/20) :
| Critère | Points |
|---|---|
| Partie 00 – mise en place, arborescence, images et dépôt | 1 |
Partie 01 – gabarit Bootstrap 5.3, navbar responsive, 5 pages reliées |
1,5 |
Partie 02 – contrôles : types HTML5, .form-select, <datalist>, couleur, fichier, curseur |
2 |
| Partie 03 – cases, radios en ligne, interrupteurs, boutons bascules | 2 |
Partie 04 – formulaire vertical : .form-text, grille, cartes, <fieldset>, readonly, analyse GET / POST |
2 |
Partie 05 – formulaires en ligne : recherche, filtres, newsletter, .visually-hidden |
2 |
Partie 06 – formulaire horizontal : .col-form-label, <legend>, .offset-*, responsive |
2 |
| Partie 07 – étiquettes flottantes, groupes de saisie, afficher / masquer le mot de passe | 2 |
Partie 08 – validation : novalidate, messages, setCustomValidity(), envoi simulé, .is-invalid |
2,5 |
| Partie 09 – mode sombre, vérifications (W3C, Lighthouse), site publié sur GitHub Pages | 1,5 |
Git / GitHub – dépôt créé en partie 00, un commit par partie avec un message clair, README.md, étiquette v1.0 |
1,5 |
| Total | 20 |
| Bonus | +2 max |
Question de réflexion (à rédiger en 5 lignes) :
Vous avez utilisé quatre dispositions de formulaires (vertical, en ligne, horizontal, étiquettes flottantes). Pour chacune, donnez un exemple de situation où elle est la plus adaptée, et expliquez pourquoi un même site peut en combiner plusieurs.
Vous avez utilisé quatre dispositions de formulaires (vertical, en ligne, horizontal, étiquettes flottantes). Pour chacune, donnez un exemple de situation où elle est la plus adaptée, et expliquez pourquoi un même site peut en combiner plusieurs.