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.
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 :
- Form Builder (Dashboard > Forms) — définir les champs, la validation et les actions
- Un champ
formIdsur 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 |
|---|---|
| name | Clé unique du champ (p. ex. email, message) |
| type | text, email, textarea, number, phone, url, date, select, multiselect, checkbox, radio, file, hidden |
| label | Libellé affiché (multilingue) |
| placeholder | Texte d'exemple (multilingue) |
| validation | required, minLength, maxLength, minValue, maxValue, pattern, customMessage |
| width | full, half ou third — contrôle la largeur du champ dans la grille du formulaire |
| options | Pour select, multiselect, radio — tableau de { value, label } |
| order | Ordre d'affichage |
3. Configurez les paramètres
| Paramètre | Description |
|---|---|
| Action Type | contact 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 Recipients | Liste des e-mails recevant les notifications du formulaire |
| Success Message | Affiché après une soumission réussie (multilingue) |
| Error Message | Affiché en cas d'échec (multilingue) |
| Submit Button Label | Texte du bouton (multilingue) |
| Save Submissions | Stocker les soumissions en base de données (par défaut : true) |
| Send Email Notification | E-mail aux destinataires à chaque soumission (par défaut : true) |
| Require Login | Seuls 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 :
| Bloc | Form Action | Description |
|---|---|---|
| Contact | contact | Formulaire de contact avec cartes d'info et citation |
| Newsletter | custom | Inscription e-mail qu'un webhook du workspace transmet à votre prestataire d'emailing |
| Demande de devis | contact | Demande 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
- L'utilisateur soumet le formulaire sur votre site publié
- Le serveur valide les champs et vérifie les limites de débit
- La soumission est enregistrée avec le statut
pending - Notification e-mail envoyée aux destinataires (si activée)
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- Le statut reste
pendingjusqu'à 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
halfetthirdpour 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