Formularios y Form Builder
Crea formularios con el Form Builder visual y conéctalos a bloques personalizados guardando el ID del formulario en un campo del bloque.
Resumen
Cmssy incluye un Form Builder integrado que te permite crear formularios visualmente y conectarlos a cualquier bloque personalizado. Los formularios gestionan la validación, los envíos, las notificaciones por email y los eventos entregados por webhook — tus bloques solo tienen que renderizar la UI.
El sistema tiene dos partes:
- Form Builder (Dashboard > Forms) — define campos, validación y acciones
- Un campo
formIden tu bloque — guarda qué formulario debe renderizar el bloque
Crear un formulario
1. Abre el Form Builder
Ve a Dashboard → Forms → Create Form. Dale un nombre y un slug (p. ej. contact-form).
2. Añade campos
Cada campo tiene:
| Propiedad | Descripción |
|---|---|
| name | Clave única del campo (p. ej. email, message) |
| type | text, email, textarea, number, phone, url, date, select, multiselect, checkbox, radio, file, hidden |
| label | Etiqueta visible (multilingüe) |
| placeholder | Texto de ejemplo (multilingüe) |
| validation | required, minLength, maxLength, minValue, maxValue, pattern, customMessage |
| width | full, half o third — controla el ancho del campo en la cuadrícula del formulario |
| options | Para select, multiselect, radio — array de { value, label } |
| order | Orden de visualización |
3. Configura los ajustes
| Ajuste | Descripción |
|---|---|
| Action Type | contact o custom — nada más se acepta. Ninguno cambia lo que el servidor hace con un envío; es una etiqueta que tu bloque puede leer para elegir un diseño. |
| Email Recipients | Lista de emails que reciben las notificaciones del formulario |
| Success Message | Se muestra tras un envío correcto (multilingüe) |
| Error Message | Se muestra en caso de fallo (multilingüe) |
| Submit Button Label | Texto del botón (multilingüe) |
| Save Submissions | Guardar los envíos en la base de datos (por defecto: true) |
| Send Email Notification | Email a los destinatarios en cada envío (por defecto: true) |
| Require Login | Solo los usuarios con sesión iniciada pueden enviar |
4. Publica
Cambia el estado a Published. Copia su ID de formulario — lo referenciarás desde tu bloque.
Usar formularios en bloques personalizados
Referenciar un formulario
Añade un campo formId al esquema de tu bloque. Usa fields.form(): muestra un selector de formularios en el editor y guarda el id del formulario elegido, así nadie tiene que copiar un id a mano.
// 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: "Formulario" }),
submitLoadingText: fields.text({ label: "Loading Text", defaultValue: "Sending..." }),
successHeading: fields.text({ label: "Success Heading", defaultValue: "Message Sent!" }),
},
});Renderizar el formulario
El SDK resuelve automáticamente cualquier formulario referenciado por el formId de un bloque e inyecta la definición en el context del bloque como context.forms[formId] — sin necesidad de hacer fetch:
// 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
}Enviar el formulario
El envío pasa por public.form.submit. Guarda la mutación en tu propio repositorio y mándala con tu cliente configurado: el SDK lleva la misma cadena como SUBMIT_FORM_MUTATION, pero bajo @cmssy/core/internal, que no es API pública. El backend valida los campos, guarda el envío, manda los correos de notificación, emite form.submitted y responde con éxito o error:
// 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 }
}El envío es la única escritura que un frontend público puede hacer sin token. Todo lo demás sobre formularios -crearlos, leer envíos, cambiar estados- necesita un cliente autorizado.
Bloques de formulario de referencia
Cmssy no incluye bloques — en el modelo headless construyes los bloques en tu propio repo con el SDK. Estos son bloques de formulario habituales que puedes implementar como patrones de referencia; cada uno conecta un formulario del Form Builder (su actionType) con un bloque que tú renderizas:
| Bloque | Form Action | Descripción |
|---|---|---|
| Contact | contact | Formulario de contacto con tarjetas de info y cita |
| Newsletter | custom | Suscripción por email que un webhook del workspace reenvía a tu proveedor de mailing |
| Solicitud de presupuesto | contact | Consulta más larga que llega a Submissions y te llega por email |
Cada uno define el formulario en el servidor con el Form Builder y lo renderiza en un bloque mediante un campo formId — el markup es del desarrollador. Consulta Autenticación de miembros para los flujos de autenticación.
El inicio de sesión, el registro y el restablecimiento de contraseña no son formularios del Form Builder: llaman directamente a las mutaciones de autenticación de miembros (login, register, forgotPassword, resetPassword).
Envíos de formulario
Ver los envíos
Ve a Dashboard → Forms → [Tu formulario] → Submissions. Cada envío muestra:
- Todos los valores de los campos
- Estado (
pending,processed,spam,archived) - Dirección IP, user agent, referrer
- Marca de tiempo
- Estado de entrega de email
Ciclo de vida de un envío
- El usuario envía el formulario en tu sitio publicado
- El servidor valida los campos y comprueba los límites de frecuencia
- El envío se guarda con estado
pending - Se manda la notificación por email a los destinatarios (si está activada)
- Se emite
form.submitted— después de guardar el envío, a cada webhook del workspace suscrito a ese evento, y un fallo de entrega nunca hace fallar el envío - El estado permanece
pendinghasta que lo cambies en la pestaña Submissions
Cómo llega un envío a un sistema externo
Registra un webhook del workspace para el evento form.submitted. Es la única vía de salida, y es la duradera: firmada, con reintentos propios, recuperada por un sweeper y visible en un registro de entregas que puedes leer y reenviar. Un formulario no tiene ajuste de webhook propio.
El evento lleva el id del envío, no las respuestas. Las lees con get_form_submission o form.submission(submissionId:) por la API, con el mismo permiso forms:submissions:view que permite a un endpoint suscribirse al evento. Así las respuestas se quedan en un solo sitio con una sola ruta de borrado, y ningún envío grande puede empujar un evento por encima del límite de tamaño y silenciarlo para el resto de suscriptores.
Protección antispam
Los formularios incluyen limitación de frecuencia integrada:
- Límite por IP y por formulario
- Los campos honeypot se pueden añadir con el tipo de campo
hidden
Referencia de tipos de acción
contact
Guarda el envío + manda un email a los destinatarios configurados. El valor por defecto para la mayoría de formularios.
custom
Una etiqueta y nada más: el servidor trata un formulario custom igual que uno contact. Úsala para marcar formularios que tu bloque renderiza de otra forma. Para llegar a un servicio externo (Zapier, Slack, un CRM), suscribe un webhook del workspace a form.submitted.
El inicio de sesión y el registro de miembros no son tipos de acción de formulario — consulta Autenticación de miembros.
Consejos
- Publica siempre tu formulario antes de referenciarlo — los formularios en borrador no se pueden resolver
- Usa los anchos
halfythirdpara crear diseños de varias columnas (p. ej. nombre + apellidos lado a lado) - Etiquetas multilingües — los campos de formulario admiten etiquetas y placeholders por idioma, en línea con el sistema de idiomas del sitio
- Los envíos de prueba se guardan como los reales — bórralos de la pestaña Submissions cuando termines
- Depuración de webhooks — abre Settings → Webhooks → Deliveries: cada intento está ahí con su código de respuesta, y puedes reenviar uno