Formulaires complexes
Quand utiliser un formulaire multi-étapes
La décision dépend du nombre de champs, du nombre de domaines métier distincts, et de la présence de données conditionnelles.
| Critère | Page unique | Multi-étapes |
|---|---|---|
| Nombre de champs | < 6 | ≥ 7 |
| Domaines métier | 1 seul | 2 ou plus |
| Temps estimé | < 2 min | > 2 min |
| Données conditionnelles | Non | Oui |
Indicateur de progression
Toujours affiché en haut du formulaire multi-étapes. Les étapes complétées sont marquées step-primary.
- Informations
- Articles
- Personnalisation
- Récapitulatif
<ul class="steps w-full mb-6"> <li class="step step-primary">Informations</li> <li class="step step-primary">Articles</li> <li class="step">Personnalisation</li> <li class="step">Récapitulatif</li> </ul>
Étape 1 : formulaire basique
Pattern standard avec fieldset DaisyUI. Label au-dessus, texte d'aide via fieldset-label.
<div class="space-y-4 max-w-md">
<fieldset class="fieldset">
<legend class="fieldset-legend">Nom du client <span class="text-error ml-0.5">*</span></legend>
<input type="text" class="input w-full" placeholder="ex. Dupont SA" required>
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">Référence interne</legend>
<input type="text" class="input w-full" placeholder="ex. CMD-2026-001">
<p class="fieldset-label">Optionnel. Laissez vide pour auto-génération.</p>
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">Type de commande <span class="text-error ml-0.5">*</span></legend>
<select class="select w-full">
<option disabled selected>Sélectionner</option>
<option>Standard</option>
<option>Production spéciale</option>
<option>Urgente</option>
</select>
</fieldset>
</div> Étape récapitulative
Toujours afficher avant la soumission finale d'une action à fort impact. Permet à l'utilisateur de vérifier et corriger avant envoi.
Récapitulatif avant envoi
- Client
- Dupont SA
- Type
- Production spéciale
- Articles
- 3 références · 450 unités
<div class="card bg-base-100 border border-base-200 shadow-sm">
<div class="card-body border-b border-base-200 bg-base-200/60 rounded-t-[var(--radius-box)]">
<h2 class="card-title text-base">Récapitulatif avant envoi</h2>
</div>
<div class="card-body">
<dl class="space-y-2 text-sm">
<div class="flex justify-between py-1 border-b border-base-200">
<dt class="text-base-content/60">Client</dt>
<dd class="font-medium">Dupont SA</dd>
</div>
<!-- autres lignes -->
</dl>
<div class="flex gap-2 mt-4">
<button class="btn btn-ghost btn-sm">← Modifier</button>
<button class="btn btn-primary btn-sm flex-1">Soumettre la commande</button>
</div>
</div>
</div> Validation
Valider au blur uniquement. Afficher l'erreur sous le champ avec input-error et fieldset-label text-error.
<fieldset class="fieldset"> <legend class="fieldset-legend">Email de contact <span class="text-error ml-0.5">*</span></legend> <input type="email" class="input input-error w-full" value="email-invalide"> <p class="fieldset-label text-error">Format d'email invalide.</p> </fieldset>
Créer ou modifier dans un bloc
Un élément d'un bloc se crée et se modifie dans la même fenêtre, par-dessus la page, là où l'on a cliqué : « + Objet » dans l'en-tête du bloc pour créer, le crayon de la ligne pour modifier. Un échec garde la fenêtre ouverte avec ses erreurs ; un succès la ferme et rafraîchit la page en place. Une fiche garde sa page de modification.
Articles 2
| Article | Qté | |
|---|---|---|
| Polo piqué · marine · M | 100 | |
| Casquette brodée · blanc | 60 |
<%# Rails: DesignSystemHelper, FormDialog, design_system/_form_dialog (once per layout) %>
<div class="card-header">
<h2>Articles</h2>
<%= form_dialog_link "Article", new_order_line_path(order) %>
</div>
…
<td><%= form_dialog_link "Modifier la ligne", edit_order_line_path(order, line), icon: "pencil-square", icon_only: true %></td>
<%# lines/new.html.erb and lines/edit.html.erb: the same form %>
<%= form_dialog(line.new_record? ? "Ajouter un article" : "Modifier « #{line.name} »") do %>
<%= form_with model: [ order, line ] do |f| %>
…
<%= f.submit class: "btn btn-secondary" %>
<%= form_dialog_cancel order_path(order) %>
<% end %>
<% end %>
# LinesController (include FormDialog)
def update
if @line.update(line_params)
redirect_from_dialog order_path(@order), notice: "Ligne modifiée."
else
render :edit, status: :unprocessable_entity
end
end