PATTERNS UX

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.

Nom du client *
Référence interne

Optionnel. Laissez vide pour auto-génération.

Type de commande *
<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.

Email de contact *

Format d'email invalide.

<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

ArticleQté
Polo piqué · marine · M100
Casquette brodée · blanc60
<%# 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

Règles

✓ < 6 champs et 1 domaine → page unique
✓ ≥ 7 champs ou 2+ domaines → multi-étapes avec indicateur de progression
✓ Toujours une étape récapitulative avant soumission d'impact fort
✓ Validation au blur uniquement (jamais keystroke par keystroke)
✗ Ne jamais désactiver le bouton Soumettre avant la soumission (risque d'UX frustrante)