Formulaires & Form Builder

Créez des formulaires avec le Form Builder visuel et connectez-les à des blocs personnalisés en stockant l'ID du formulaire dans un champ de bloc.

31 mars 2026

Vue d'ensemble

Cmssy intègre un Form Builder qui vous permet de créer des formulaires visuellement et de les connecter à n'importe quel bloc personnalisé. Les formulaires gèrent la validation, les soumissions, les notifications par e-mail et les événements livrés par webhook — vos blocs n'ont qu'à rendre l'UI.

Le système comporte deux parties :

  1. Form Builder (Dashboard > Forms) — définir les champs, la validation et les actions
  2. Un champ formId sur votre bloc — stocke quel formulaire le bloc doit rendre

Créer un formulaire

1. Ouvrez le Form Builder

Allez dans Dashboard → Forms → Create Form. Donnez-lui un nom et un slug (p. ex. contact-form).

2. Ajoutez des champs

Chaque champ possède :

PropriétéDescription
nameClé unique du champ (p. ex. email, message)
typetext, email, textarea, number, phone, url, date, select, multiselect, checkbox, radio, file, hidden
labelLibellé affiché (multilingue)
placeholderTexte d'exemple (multilingue)
validationrequired, minLength, maxLength, minValue, maxValue, pattern, customMessage
widthfull, half ou third — contrôle la largeur du champ dans la grille du formulaire
optionsPour select, multiselect, radio — tableau de { value, label }
orderOrdre d'affichage

3. Configurez les paramètres

ParamètreDescription
Action Typecontact ou custom — rien d'autre n'est accepté. Aucun des deux ne change ce que le serveur fait d'une soumission ; c'est une étiquette que votre bloc peut lire pour choisir une mise en page.
Email RecipientsListe des e-mails recevant les notifications du formulaire
Success MessageAffiché après une soumission réussie (multilingue)
Error MessageAffiché en cas d'échec (multilingue)
Submit Button LabelTexte du bouton (multilingue)
Save SubmissionsStocker les soumissions en base de données (par défaut : true)
Send Email NotificationE-mail aux destinataires à chaque soumission (par défaut : true)
Require LoginSeuls les utilisateurs connectés peuvent soumettre

4. Publiez

Passez le statut à Published. Copiez son ID de formulaire — vous le référencerez depuis votre bloc.

Utiliser les formulaires dans des blocs personnalisés

Référencer un formulaire

Ajoutez un champ formId au schéma de votre bloc. Utilisez fields.form() : il affiche un sélecteur de formulaire dans l'éditeur et stocke l'identifiant du formulaire choisi - personne n'a à recopier un ID à la main.

// blocks/contact/block.ts
import { defineBlock, fields } from "@cmssy/react";
import Contact from "./Contact";

export const contactBlock = defineBlock({
  type: "contact",
  label: "Contact",
  component: Contact,
  props: {
    formId: fields.form({ label: "Formulaire" }),
    submitLoadingText: fields.text({ label: "Loading Text", defaultValue: "Sending..." }),
    successHeading: fields.text({ label: "Success Heading", defaultValue: "Message Sent!" }),
  },
});

Rendre le formulaire

Le SDK résout automatiquement tout formulaire référencé par le formId d'un bloc et injecte la définition dans le context du bloc sous context.forms[formId] — aucun fetch nécessaire :

// blocks/contact/src/Contact.tsx
export default function Contact({ content, context }) {
  const { formId } = content;
  const formDef = formId ? context?.forms?.[formId] ?? null : null;
  // formDef.fields   - array of field definitions
  // formDef.settings - submit label, messages, action type
  // ...render the fields
}

Soumettre le formulaire

La soumission passe par public.form.submit. Gardez la mutation dans votre dépôt et envoyez-la avec votre client configuré : le SDK porte la même chaîne sous SUBMIT_FORM_MUTATION, mais dans @cmssy/core/internal, qui n'est pas une API publique. Le backend valide les champs, enregistre la soumission, envoie les e-mails de notification, émet form.submitted et répond par un succès ou une erreur :

// blocks/contact/actions.ts
"use server";
import { createCmssyClient, type CmssyFormSubmitResponse } from "@cmssy/react";
import { cmssy } from "@/cmssy.config";

const SUBMIT_FORM = `mutation SubmitForm($formId: ID!, $input: SubmitFormInput!) {
  public {
    form {
      submit(formId: $formId, input: $input) {
        success
        message
        submissionId
        redirectUrl
      }
    }
  }
}`;

const client = createCmssyClient(cmssy);

export async function submitForm(formId: string, data: Record<string, string>) {
  const res = await client.query<{
    public: { form: { submit: CmssyFormSubmitResponse } };
  }>(SUBMIT_FORM, { formId, input: { data } });

  return res.public.form.submit; // { success, message, submissionId, redirectUrl }
}

La soumission est la seule écriture qu'un frontend public peut effectuer sans jeton. Tout le reste - créer des formulaires, lire les soumissions, changer un statut - exige un client autorisé.

Blocs de formulaire de référence

Cmssy ne fournit pas de blocs — dans le modèle headless, vous construisez les blocs dans votre propre repo avec le SDK. Voici des blocs de formulaire courants à implémenter comme patrons de référence, chacun reliant un formulaire du Form Builder (son actionType) à un bloc que vous rendez :

BlocForm ActionDescription
ContactcontactFormulaire de contact avec cartes d'info et citation
NewslettercustomInscription e-mail qu'un webhook du workspace transmet à votre prestataire d'emailing
Demande de deviscontactDemande plus longue qui arrive dans Submissions et vous est envoyée par e-mail

Chacun définit le formulaire côté serveur dans le Form Builder et le rend dans un bloc via un champ formId — le markup appartient au développeur. Voir Authentification des membres pour les flux d'authentification.

La connexion, l'inscription et la réinitialisation du mot de passe ne sont pas des formulaires du Form Builder : ils appellent directement les mutations d'authentification des membres (login, register, forgotPassword, resetPassword).

Soumissions de formulaire

Consulter les soumissions

Allez dans Dashboard → Forms → [Votre formulaire] → Submissions. Chaque soumission affiche :

  • Toutes les valeurs des champs
  • Le statut (pending, processed, spam, archived)
  • Adresse IP, user agent, referrer
  • Horodatage
  • Statut de livraison e-mail

Cycle de vie d'une soumission

  1. L'utilisateur soumet le formulaire sur votre site publié
  2. Le serveur valide les champs et vérifie les limites de débit
  3. La soumission est enregistrée avec le statut pending
  4. Notification e-mail envoyée aux destinataires (si activée)
  5. form.submitted émis — après l'enregistrement de la soumission, vers chaque webhook du workspace abonné à cet événement, et un échec de livraison ne fait jamais échouer la soumission
  6. Le statut reste pending jusqu'à ce que vous le changiez dans l'onglet Submissions

Faire parvenir une soumission à un système externe

Enregistrez un webhook du workspace sur l'événement form.submitted. C'est la seule voie sortante, et c'est la voie durable : signée, relancée sur son propre échelonnement, rattrapée par un sweeper, et visible dans un journal de livraison que vous pouvez lire et rejouer. Un formulaire n'a pas de réglage de webhook propre.

L'événement porte l'id de la soumission, pas les réponses. Relisez-les avec get_form_submission ou form.submission(submissionId:) via l'API, sur la même permission forms:submissions:view qui autorise un endpoint à s'abonner à l'événement. Les réponses restent alors à un seul endroit avec un seul chemin de suppression, et aucune soumission volumineuse ne peut pousser un événement au-delà de la limite de taille et le faire taire pour tous les autres abonnés.

Protection anti-spam

Les formulaires incluent une limitation de débit intégrée :

  • Limite par IP et par formulaire
  • Des champs honeypot peuvent être ajoutés avec le type de champ hidden

Référence des types d'action

contact

Sauvegarde la soumission + envoie un e-mail aux destinataires configurés. Le choix par défaut pour la plupart des formulaires.

custom

Une étiquette, rien de plus : le serveur traite un formulaire custom exactement comme un contact. Servez-vous en pour marquer les formulaires que votre bloc rend différemment. Pour atteindre un service externe (Zapier, Slack, un CRM), abonnez un webhook du workspace à form.submitted.

La connexion et l'inscription des membres ne sont pas des types d'action de formulaire — voir Authentification des membres.

Conseils

  • Publiez toujours votre formulaire avant de le référencer — les formulaires en brouillon ne peuvent pas être résolus
  • Utilisez les largeurs half et third pour créer des mises en page multi-colonnes (p. ex. prénom + nom côte à côte)
  • Libellés multilingues — les champs de formulaire prennent en charge des libellés et placeholders par langue, en phase avec le système de langues du site
  • Les soumissions de test sont enregistrées comme les vraies — supprimez-les de l'onglet Submissions une fois terminé
  • Débogage des webhooks — ouvrez Settings → Webhooks → Deliveries : chaque tentative y figure avec son code de réponse, et vous pouvez en rejouer une