
# Succès et erreurs de formulaire

La soumission est validée et la requête revient. Ce qui se passe alors à l'écran relève d'une décision produit, pas d'une décision technique : un ticket de support veut un numéro de référence, une inscription à une newsletter veut rester en place pour accepter une autre adresse, un tunnel d'achat veut passer à la suite.

`onSuccess` et `onError` rendent cette décision déclarative :

```yaml
forms:
  - id: 1
    name: contact
    title: Contact Sales
    submitTo: { table: leads }
    fields:
      - { kind: table-field, column: email, required: true }
    onSuccess:
      type: successPage
      title: Thank you
      message: We received your message and will reply within one business day.
    onError:
      type: message
      message: Something went wrong saving your request. Please try again.
```

## Types de `onSuccess`

`onSuccess` est une union discriminée par `type`. Chaque type porte ses propres propriétés.

| `type`        | Propriétés                                                                  | Comportement                                                                      |
| ------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `successPage` | `title`, `message`, `buttonLabel`, `buttonHref`, `actions[]`, `showSummary` | Remplace le formulaire par un écran de succès.                                    |
| `redirect`    | `url` (obligatoire), `delaySeconds`                                         | Navigue ailleurs. `delaySeconds` vaut `2` par défaut ; `0` navigue immédiatement. |
| `reset`       | `message`, `preserveFields[]`                                               | Vide le formulaire pour une nouvelle saisie, en conservant les champs listés.     |
| `toast`       | `message` (obligatoire), `variant` (`success` \| `info`)                    | Affiche une notification passagère et laisse le formulaire rempli en place.       |
| `message`     | `message` (obligatoire)                                                     | Remplace le formulaire par un message en ligne.                                   |

Omettez `onSuccess` et le formulaire retombe sur un toast `success` affichant « Submitted. » — un défaut raisonnable, rarement celui qu'on veut en production.

`reset` est le type indiqué pour un formulaire sur une seule page qu'un contributeur remplit à répétition. Sur une mise en page `multi-step`, il vide bien les réponses mais ne ramène pas le contributeur à la première étape : préférez-y `successPage` assorti d'une action `reset`.

## Actions de la page de succès

Une `successPage` peut proposer une suite au contributeur. Chaque entrée d'`actions[]` est rendue sous forme de bouton :

```yaml
onSuccess:
  type: successPage
  title: Ticket received
  message: Our team has been notified.
  showSummary: true
  actions:
    - { label: Submit another, action: reset }
    - { label: Back to help centre, action: navigate, url: /help }
```

| Propriété | Description                                                                         | Défaut       |
| --------- | ----------------------------------------------------------------------------------- | ------------ |
| `label`   | Texte du bouton. Prend en charge les clés `$t:`.                                    | Obligatoire. |
| `action`  | `reset` restitue le formulaire vide ; `navigate` envoie le contributeur vers `url`. | Obligatoire. |
| `url`     | Cible de navigation. Obligatoire pour `navigate`, ignorée par `reset`.              | —            |

`showSummary: true` récapitule les valeurs soumises sous le message. Le récapitulatif ignore les champs masqués et applique les permissions de lecture par champ : il ne montre jamais au contributeur une donnée qu'il n'avait pas le droit de relire.

## Variables de gabarit

Le texte de succès et la cible de redirection peuvent citer la soumission qui vient d'avoir lieu. Trois variables sont substituées au moment de l'envoi, aussi bien dans `title` et `message` que dans `url` :

| Variable           | Se résout en                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------ |
| `$submission.id`   | L'identifiant de la ligne de registre. Vide si `submitTo.storeSubmission` vaut `false`.          |
| `$record.id`       | L'identifiant de la ligne dans la table liée. Vide si le formulaire n'a pas de `submitTo.table`. |
| `$record.<column>` | Une colonne de la ligne insérée — mais uniquement une colonne fournie par le contributeur.       |

```yaml
onSuccess:
  type: redirect
  url: /thank-you?ref=$submission.id
  delaySeconds: 0
```

Les valeurs substituées dans une `url` sont encodées en pourcentage : une adresse e-mail survit donc intacte à la chaîne de requête. La restriction sur `$record.<column>` est délibérée : les colonnes calculées côté serveur et les colonnes privilégiées ne sont jamais exposées via une URL de redirection, si tentant que soit le raccourci.

:::callout
**Une variable non résolue devient une chaîne vide, jamais le jeton littéral.** Un `$record.id` sur un formulaire sans table liée se substitue en rien : `/done?recId=$record.id` navigue donc vers `/done?recId=`. La redirection part quand même et la soumission reste enregistrée — vous obtenez un paramètre silencieusement vide plutôt qu'une URL cassée ou une chaîne de gabarit divulguée. Vérifiez que la page cible tolère une valeur vide avant d'en insérer une.
:::

## `onError`

`onError` couvre les échecs portant sur la soumission entière — l'écriture a été refusée, la requête n'a pas abouti.

| Propriété | Description                                                  | Défaut       |
| --------- | ------------------------------------------------------------ | ------------ |
| `type`    | `toast`, `message` (en ligne) ou `errorPage` (page entière). | Obligatoire. |
| `message` | Corps du message. Prend en charge les clés `$t:`.            | Obligatoire. |
| `title`   | Titre, utilisé par `errorPage`.                              | —            |
| `variant` | `error` ou `warning`. N'a de sens que pour `type: toast`.    | `error`      |

Omis, il retombe sur un toast affichant « Submission failed. »

Les erreurs de validation par champ empruntent un autre canal. Une adresse e-mail invalide ou une valeur obligatoire manquante revient sous forme de liste `fieldErrors` et s'affiche en ligne contre la saisie fautive — `onError` se déclenche en parallèle comme synthèse du formulaire, et non à sa place.

## Pages associées

- [Soumissions](/fr/docs/form-submissions) — l'écriture double qui doit être validée avant que `onSuccess` s'exécute.
- [Champs de formulaire](/fr/docs/form-fields) — les permissions de lecture par champ que `showSummary` respecte.
- [Formulaires multi-étapes](/fr/docs/form-multi-step) — ce que « après la dernière étape » signifie pour ces types.
- [Présentation des formulaires](/fr/docs/forms-overview) — la place de `onSuccess` et `onError` dans le schéma complet.
