Zum Inhalt springen

Felder und Widgets

Jedes Feld hat name und type. Dazu kommen optional validator (Server-Regeln) und meta (Admin-Darstellung). Beispiele unten stammen aus content.yml, navigation.yml, medialib.yml und tag.yml.

content.yml — Pflichtfeld mit Pattern plus Hilfetext
# aus content.yml — Pflichtfeld mit Pattern plus Hilfetext
- name: path
type: string
validator:
pattern: ^\/[a-z0-9\-\/]*$
required: true
meta:
label: { de: "Pfad", en: "Path" }
helperText:
de: "URL-Pfad für diese Seite, z.B. '/ueber-uns'."
en: "URL path for this page, e.g. '/about-us'."
  • name passt auf ^[0-9A-Za-z_-]+$ — keine Punkte, keine Leerzeichen.
  • object und object[] tragen ihre Unterfelder in subFields.
  • Listen hängst du per [] an: string[], object[], file[].
  • meta.hide: true versteckt Technikfelder (_pagebuilderThumbnail, _testdata).

Das Schema kennt elf Typen. Das Widget wählst du in meta.widget.

Server-Typ Bedeutung Widget im Starter
string Text, eine Zeile Standard; select, richtext, textarea, foreignKey, foreignMedia, color-nah via select
string[] Textliste foreignKey mit foreign: { collection: tag } (medialib.yml: tags)
number Zahl number
number[] Zahlenliste number
boolean Ja/Nein Standard-Checkbox/switch; reine Flags ohne Widget (comment.yml: active)
object Gruppe containerLessObject (kein Kasten), Standard mit Kasten
object[] Liste von Gruppen containerLessObjectArray, pagebuilder (content.yml: blocks)
file Upload file (medialib.yml), image
file[] Mehrere Uploads file
date Datum/Zeit date, datetime (content.yml: publication.from)
any Alles erlaubt json

Alle prüfbaren Widgets aus dem Schema (field-meta.schema.json, widget-Enum, 25 Werte):

Widget Wofür
text Einzeiliger Text (Standard)
textarea Mehrzeiliger Text
number Zahleneingabe
checkbox, switch Ja/Nein-Umschalter
select Dropdown aus meta.choices
selectArray, chipArray Mehrfach-Auswahl als Liste bzw. Chips
date, datetime Datum bzw. Datum mit Uhrzeit
file Datei-Upload (auch file[])
image Bild-Upload mit Vorschau
json Freies JSON (any-Felder)
richtext, html Formatierter Text bzw. HTML-Quelltext
foreignKey, foreignKeyChipArray Verweis auf andere Sammlung (einfach / mehrfach)
foreignFile Datei-Verweis auf andere Sammlung
foreignMedia Bild-Verweis auf die Mediathek
pagebuilder Block-Editor für object[]
templateProps Vorlagen-Parameter
containerLessObject, containerLessObjectArray Gruppe(n) ohne umgebenden Kasten
color Farbauswahl

Der Server prüft validator bei POST und PUT. Leere Strings bestehen required nicht — außer mit allowZero: true.

Schlüssel Wirkung Beispiel aus dem Starter
required: true Feld muss gefüllt sein content.yml: name, path; navigation.yml: language, type
pattern Regulärer Ausdruck path: ^\/[a-z0-9\-\/]*$; hash: ^[a-zA-Z0-9_-]+$
in Nur diese Werte navigation.yml: language in ["de", "en"], type in ["header", "footer"]
minLength / maxLength Zeichenlänge elements.name: maxLength: 100; alt.de: maxLength: 500
min / max Zahlenbereich —
minDate / maxDate Datumsbereich —
minItems / maxItems Listenlänge —
format email, url, uuid oder slug —
maxFileSize / minFileSize Dateigröße ("50MB") medialib.yml: file mit required: true, maxFileSize: "50MB"
accept Erlaubte MIME-Typen —
eval Eigene JavaScript-Regel —
allowZero Leere Werte trotz required erlauben —

meta.choices listet id plus name (de/en). Mit widget: select wird daraus ein Dropdown.

navigation.yml — feste Auswahl mit choices
# aus navigation.yml
- name: language
type: string
validator:
in: ["de", "en"]
required: true
meta:
label: { de: "Sprache", en: "Language" }
widget: select
choices:
- id: de
name: { de: "Deutsch", en: "German" }
- id: en
name: { de: "Englisch", en: "English" }

Leerer id: "" heißt „Standard/keine Auswahl” (containerWidth, padding in content.yml).

meta.foreign verweist auf eine andere Sammlung. Der Admin zeigt dann einen Auswahl-Dialog statt einem Textfeld.

navigation.yml — Fremdschlüssel auf content
# aus navigation.yml — Seite verweist auf content
- name: page
type: string
meta:
label: { de: "Seite", en: "Page" }
widget: foreignKey
foreign:
collection: content
id: id
Widget Wofür Beispiel
foreignKey Ein Verweis (ID als String) navigation.elements.page → content; comment.contentId → content; medialib.tags → tag
foreignMedia Bild aus der Mediathek content.yml: blocks.heroImage.image, blocks.image → medialib
foreignFile / foreignKeyChipArray Datei-Verweis / Mehrfach-Verweis laut Schema verfügbar

Auflösen musst du den Verweis beim Lesen per lookup — siehe Lesen und suchen.

meta.dependsOn.eval ist JavaScript. $parent ist das umgebende Objekt — so zeigt der Pagebuilder nur passende Felder.

content.yml — Unterzeile nur beim Hero-Block
# aus content.yml — Unterzeile nur beim Hero-Block
- name: subline
type: string
meta:
label: { de: "Unterzeile", en: "Subline" }
dependsOn:
eval: $parent.type == 'hero'

Weitere Muster aus content.yml zum Kopieren:

  • Mehrere Typen: $parent.type == 'features' || $parent.type == 'richtext' || $parent.type == 'accordion' || $parent.type == 'contact-form'
  • Negation: $parent.type != '' (Block-Ausschalter hide)

Zwei Muster kommen im Starter vor:

medialib.yml — Alt-Text je Sprache
# aus medialib.yml — Alt-Text je Sprache
- name: alt
type: object
meta:
label: { de: "Alt-Text", en: "Alt Text" }
subFields:
- name: de
type: string
validator:
maxLength: 500
- name: en
type: string
validator:
maxLength: 500

Je Option eine Zeile (Quelle: tibi-types/schemas/config/field-meta.schema.json):

Option Wirkung Typ / Beispiel
hideLabel Blendet das Feld-Label im Formular aus boolean; hideLabel: true
imageEditor Bildbearbeitung im Uploader boolean oder { crop, rotate, flip, focalPoint, adjust, palette }; imageEditor: { crop: true, rotate: true }
containerProps Feld-Wrapper (class, layout mit breakBefore, breakAfter, size mit default/small/large) Objekt; containerProps: { layout: { breakBefore: true } }
inputProps Wird ans Eingabeelement durchgereicht (widget-spezifisch) Objekt (additionalProperties: true)
schemaRef Schema des Felds aus einem anderen Feld übernehmen { field } + optional ref; schemaRef: { field: blocks }
protected Schreibschutz vor fremdem Überschreiben (Bool oder UI-Bedingung) boolOrUiCondition; protected: true
drillDown false rendert den Pagebuilder inline statt im Overlay boolean; drillDown: false (siehe Pagebuilder-Anbindung)
pageSize Seitengröße für paginierte Feldlisten integer ≥ 0; pageSize: 20

Verifiziert am e3f92eb 2026-10-17 (tibi-svelte-starter), am 4c55f82 2026-10-17 (tibi-types), am 68b4278 2026-10-17 (tibi-server, validator.go); Meta-Ergänzungen verifiziert am 4c55f82 2026-10-17 (tibi-types: field-meta.schema.json)