Formulare
Formulare im visuellen Builder: Vorlagen, Feldtypen, Abschnitte und Schritte, Bedingungen („wenn … dann anzeigen“) und Validierung, die auf Server und Client identisch gilt; Einsendungen, Benachrichtigungen, Spam-Schutz und die Anbindung an SmartCaptcha und Hellolead.
Stand: 20.10.2026
Auf dieser Seite
Formulare sammeln Nachrichten von Besuchern: Kontakt, Rückruf, Terminanfrage, Bewerbung. Das Frontend rendert sie anhand der im Admin definierten Felder — es muss nichts doppelt gepflegt werden. Formulare gehören zur Website und werden unter Formulare verwaltet.
Vorlagen
Ein neues Formular startet wahlweise leer oder aus einer Vorlage:
| Vorlage | Felder |
|---|---|
| Kontakt | Name, E-Mail, Telefon, Nachricht, Datenschutz-Einwilligung |
| Kontakt mit Rückruf | Abschnitte „Kontaktdaten“, „Anliegen“, „Rückruf“; Telefon und Wunschzeit erscheinen nur, wenn „Rückruf gewünscht“ angehakt ist, die Auftragsnummer nur beim Thema „Support“ |
| Rückruf-Bitte | Name, Telefon, Wunschzeit (vormittags / nachmittags / abends) |
| Terminanfrage | Name, E-Mail, Wunschtermin, Uhrzeit, Anliegen |
| Angebotsanfrage | Name, Firma, E-Mail, Budgetrahmen, Beschreibung |
| Bewerbung | Name, E-Mail, Telefon, Position, Wunschtermin, Lebenslauf als Datei |
Alle Beschriftungen liegen zweisprachig (DE/EN) vor und lassen sich je Sprache ändern.
Der Builder
Ein Formular wird im visuellen Builder zusammengestellt — drei Bereiche nebeneinander:
- Palette (links): alle Feldtypen sowie „Abschnitt“ und „Schritt“. Ein Klick hängt das Element an die gewählte Gruppe an, Ziehen legt es an einer bestimmten Stelle ab.
- Aufbau (Mitte): Gruppen als Karten, Felder als Zeilen mit Griff, Beschriftung, Typ, Pflicht-Punkt und einem Verzweigungs-Symbol, wenn eine Bedingung gesetzt ist. Felder lassen sich per Drag & Drop zwischen Gruppen verschieben; mit der Tastatur geht es per Enter (auswählen), Alt+↑/↓ (verschieben) und Entf (entfernen). Jede Bewegung wird Screenreadern angesagt.
- Einstellungen oder Vorschau (rechts): Beschriftung, Platzhalter und Hilfetext je Sprache, Feldname (mit Schloss gesichert, automatisch aus der Beschriftung), Pflicht, Breite, Validierung, Optionen, Standardwert und Bedingungen. Die Live-Vorschau rendert das Formular mit derselben Logik wie die Website — Werte eingeben, und bedingte Felder erscheinen; Schritte laufen als Wizard. Ein Umschalter zeigt Desktop oder Mobil.
Gespeichert wird mit ⌘S oder dem Button — Aufbau und Einstellungen in einem Zug (PUT admin/forms/:id/layout für die Struktur, PATCH admin/forms/:id für den Rest). Ein leeres Formular bietet zuerst Aus Vorlage starten an; die Vorlage wird in den Builder übernommen und kann vor dem Speichern angepasst werden.
Felder
Jedes Feld hat einen Namen (Schlüssel, unter dem die Antwort in Einsendungen und API erscheint), einen Typ, Beschriftung, Platzhalter und Hilfetext je Sprache, eine Breite, Pflichtangabe, Standardwert und Validierungsregeln. Feldtypen: Text, mehrzeiliger Text, E-Mail, Telefon, Datum, Auswahl, Optionsfelder, Checkbox, Datei, verstecktes Feld, Einwilligung.
Pflichtfelder sparsam setzen: Jedes Pflichtfeld kostet Absendungen. Name und eine Kontaktmöglichkeit reichen meistens.
Breite: 1/1, 1/2 oder 1/3 der Zeile — die Zeilen im Aufbau zeigen die Breite, die Website rendert ein entsprechendes Raster. Auf dem Handy bekommt jedes Feld volle Breite. Formulare ohne eigene Breiten rendern wie bisher (einzeilige Felder paarweise, mehrzeilige darunter).
Hilfetext: steht unter dem Feld und ist per aria-describedby mit ihm verknüpft — Screenreader lesen ihn zusammen mit der Beschriftung.
Abschnitte und Schritte
Felder lassen sich in Gruppen zusammenfassen:
- Ein Abschnitt rendert als
fieldsetmit Überschrift (legend) und optionaler Beschreibung. - Ein Schritt macht das Formular mehrstufig: Besucher sehen die Schritte nacheinander mit Fortschrittsbalken, „Weiter“ und „Zurück“. Vor dem Wechsel werden die Felder des aktuellen Schritts geprüft. Felder ohne Gruppe erscheinen auf der ersten Seite, Einwilligungen ohne Gruppe auf der letzten; Abschnitte folgen dem Schritt, der vor ihnen liegt.
Gruppen haben eine eigene Reihenfolge und können — wie Felder — eine Bedingung tragen. Wird eine Gruppe aufgelöst, bleiben ihre Felder erhalten und wandern auf die oberste Ebene.
Bedingungen — „wenn der Haken gesetzt ist, dann das Feld anzeigen“
Jedes Feld und jede Gruppe kann nur unter einer Bedingung sichtbar sein. Im Builder liest sich das als Satz: „Dieses Feld anzeigen, wenn alle | eine der Regeln zutreffen“. Je Regel wählt man ein früheres Feld, einen zum Typ passenden Vergleich und — wo nötig — einen Wert:
| Feldtyp | Vergleiche |
|---|---|
| Checkbox, Einwilligung | ist angehakt · ist nicht angehakt |
| Auswahl, Optionsfelder | ist · ist nicht · ist eines von · ist leer · ist ausgefüllt (Wert aus den Optionen) |
| Text, E-Mail, Telefon | ist · ist nicht · enthält · enthält nicht · ist leer · ist ausgefüllt · größer/kleiner als |
| Datum | ist · ist nicht · größer/kleiner als (also nach/vor) · ist leer · ist ausgefüllt |
| Datei | ist leer · ist ausgefüllt |
Unter den Regeln steht die Bedingung in Klartext, zum Beispiel „Wird angezeigt, wenn ‚Rückruf gewünscht‘ angehakt ist“ — derselbe Text erscheint als Tooltip am Verzweigungs-Symbol der Feldzeile.
Gespeichert wird die Bedingung als condition_json:
{
"logic": "all",
"rules": [
{ "field": "callback", "op": "checked" },
{ "field": "topic", "op": "in", "value": ["sales", "support"] }
]
}Operatoren: equals, not_equals, contains, not_contains, is_empty, is_not_empty, checked, unchecked, gt, lt, in. Das Ergebnis ist immer „anzeigen“.
Regeln, die überall gleich gelten:
- Versteckte Felder sind nie Pflicht und ihre Werte werden beim Absenden verworfen — im Browser, im Website-Proxy und im Backend, mit ein und derselben Auswertungslogik (
form-conditions.ts, als identische Kopie in Backend, Website und Admin). - Felder in einer versteckten Gruppe sind versteckt. Ein verstecktes Feld zählt für andere Regeln als leer — Sichtbarkeit kaskadiert.
- Keine Kreise: Ein Feld darf nicht von sich selbst oder von Feldern abhängen, die ihrerseits von ihm abhängen. Der Builder bietet nur frühere Felder an; das Backend prüft beim Speichern und antwortet mit
400samt Feldnamen, falls doch ein Zyklus oder ein unbekanntes Feld referenziert wird.
Validierung — einmal definiert, zweimal geprüft
Die Regeln liegen je Feld als JSON und werden von derselben Engine auf dem Server (beim Absenden) und im Browser (vor dem Absenden) ausgewertet. Das Frontend bekommt die Regeln über die Delivery API mitgeliefert und zeigt Fehler sofort, der Server entscheidet endgültig.
{
"required": true,
"minLength": 2, "maxLength": 120,
"type": "email",
"pattern": "^[0-9]{5}$", "flags": "i",
"patternMessage": { "de": "Bitte eine fünfstellige PLZ eingeben." },
"sameAs": "email",
"allowedExtensions": ["pdf", "jpg"], "maxSizeKb": 5120,
"messages": { "required": { "de": "Bitte ausfüllen." } }
}Typ-Voreinstellungen: email, tel, url, number, integer, date, postalCode (mit Land), iban. Der Feldtyp impliziert ein Preset (E-Mail-Feld → email), validation.type gewinnt, wenn beides gesetzt ist. Fehlermeldungen lassen sich je Regel und Sprache überschreiben.
Formular im Frontend
Definition abrufen:
curl "https://entrydeck.app/api/v1/delivery/form/kontakt" \
-H "x-api-key: $ENTRYDECK_API_KEY"Die Antwort enthält groups (Abschnitte und Schritte mit id, kind, label, description, condition) und fields — je Feld Beschriftungen, Platzhalter, help, die aufgelösten Regeln, groupId, width, default und condition — sowie, falls aktiv, den öffentlichen SmartCaptcha-Site-Key samt Widget-URL. Das Secret verlässt den Server nie.
Absenden:
await $fetch(`/forms/${form.id}/submissions`, {
method: 'POST',
baseURL: 'https://entrydeck.app/api/v1',
headers: { 'x-api-key': apiKey },
body: { data: { name: 'Erika Muster', email: 'erika@example.org', message: 'Hallo!' }, locale: 'de' },
})Der Server wertet zuerst die Bedingungen aus (unsichtbare Felder werden verworfen und nie als Pflicht behandelt), prüft dann die Regeln der sichtbaren Felder, wertet Honeypot und Captcha aus, speichert die Einsendung und antwortet mit 201 oder 422 samt errors — einer Liste von Feldname zu Meldung. Rate-Limits (3 pro Minute je Adresse) schützen vor Massenversand.
Einsendungen
Alles, was hereingekommen ist, liegt unter Formulare → Einsendungen — mit Zeitstempel, allen Feldern und einem Status (offen, erledigt, Spam) für die Arbeit im Team. Der CSV-Export enthält die aktuell gefilterten Einsendungen. Einsendungen enthalten meist personenbezogene Daten: Was nicht mehr gebraucht wird, sollte gelöscht werden — pro Eintrag möglich.
Automatisch geht es mit Aufbewahrung der Einsendungen in den Formular-Einstellungen: unbegrenzt, 30 Tage, 90 Tage, 180 Tage, 1 Jahr, 2 Jahre oder eine eigene Anzahl Tage. Jede Nacht um 03:30 löscht das System Einsendungen, die älter sind, und vermerkt die Anzahl im Audit-Log; bereits verschickte Benachrichtigungen und an Hellolead übergebene Leads bleiben davon unberührt.
Benachrichtigungen
Eine Empfängeradresse je Formular sorgt dafür, dass niemand die Liste im Blick behalten muss. Ohne Empfänger liegen Einsendungen still im System.
Spam-Schutz
- Honeypot-Feld: ein unsichtbares Feld, das nur Bots ausfüllen.
- Mindestdauer bis zum Absenden.
- SmartCaptcha (Add-on): unsichtbare Prüfung ohne Bilderrätsel, Entscheidung serverseitig, je Formular ein- und ausschaltbar — siehe Add-ons.
Leads weitergeben
Mit dem Add-on Hellolead wird jede Einsendung als Lead übergeben — mit Feldzuordnung je Formular und ohne Copy-und-paste. Ein Fehler bei der Übergabe blockiert nie den Eingang: Die Einsendung wird immer gespeichert, die Übergabe protokolliert.
Newsletter
Anmeldungen zum Newsletter laufen über ein eigenes Formular mit Double-Opt-in: Die Adresse wird per Bestätigungslink verifiziert, Abmeldungen bleiben als abgemeldet geführt (damit dieselbe Adresse nicht versehentlich erneut importiert wird). Der CSV-Export liefert Adresse, Status und Anmeldedatum für den Versanddienst.