Field Types
Krios ships eleven built-in field types plus a custom-field-type registry for extension via iframe-rendered widgets.
Built-in types
| Type | When to use |
|---|---|
text | One-line strings, short paragraphs, slugs that don't need conflict checks. Optional validations.regex + patternName (Email, URL, Phone, Hex Color, Alphanumeric, Letters Only, Custom). |
richtext | Long-form authored content — paragraphs, headings, lists, embeds. Stored as a structured AST; renders to HTML at delivery. |
number | Integers / floats. Optional min / max. |
boolean | Single checkbox. |
datetime | ISO 8601 timestamps. validations.dateOnly = true for pure dates. |
media | Reference to a MediaAsset. validations.allowedAssets constrains kinds + extensions. |
reference | Pointer to another entry. allowedTypeIds restricts which content types are valid. |
enum | Predefined option set. Field create requires a non-empty enumValues: string[] (omitting it → 422 enum_requires_values). validations.enumOptions: [{ key, label, description? }] is optional metadata that adds labels/descriptions. Multi-select is controlled by the field's isMultiple flag — the same flag reference / media use — not a separate enum-only toggle. |
blocks | Ordered list of embedded entries (page composition). Requires a non-empty allowedTypeIds (empty → 422 blocks_require_types) — unlike reference, it does not treat empty as "any type". |
slug | URL segment. The slug comes from the entry's slug (or is derived from the tree path at routing time), with a manual per-entry override. |
link | Compound link with `mode: internal |
Engineering notes
- richtext stores a structured AST (close to ProseMirror's shape). Validation runs in
lib/richtext/validate.tsand rejects documents that violate the field'srichTextConfig. See Rich text. - media stores asset IDs (or arrays). The validator looks the IDs up to confirm they exist + match the kind/extension policy.
- reference / blocks store entry IDs. The reference table (
ContentReference) is bidirectional — used for "Where used" + reference-safe delete. - link is a compound JSON value with a
modediscriminator. Seelib/links/index.tsfor the validator and effective config. - enum stores option keys. The required input is
enumValues: string[]— the canonical option list;validations.enumOptions([{ key, label, description? }]) is optional metadata for labels/descriptions and is not auto-synced withenumValues. - slug takes its value from the entry's
slug, or derives it from the tree path (TreeNode.path) at routing time; either way a manual per-entry override wins. There is novalidations.slugFromTreePathconfig key.
Custom field types
Custom field types render as an iframe in the entry editor and communicate via postMessage. The CMS persists the value as JSON; values are validated against a JSON Schema on every save.
# Register via the admin UI (Settings → Custom fields) or via REST:
curl -X POST -H "Authorization: Bearer $MK" -H "Content-Type: application/json" \
http://localhost:3000/api/v1/projects/demo/custom-field-types \
-d '{
"name": "Color picker",
"apiName": "colorPicker",
"hostedUrl": "https://my-widget.example.com",
"validationSchema": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" }
}'
Once registered, colorPicker shows up in the field-type dropdown alongside the eleven built-ins. Storage uses the custom:colorPicker prefix so the field-definition table doesn't need a schema change. See @krios/custom-element-sdk for the widget side.
Per-field flags
| Flag | Effect |
|---|---|
isRequired | Publish gate: required fields must have a value before the entry can be published. |
isLocalizable | One value per locale (otherwise stored under __shared). |
isMultiple | Field stores an array (applies to reference, media, enum). |
isSearchable | Value contributes to the entry's full-text search index. |
isFilterable | Advisory in V1. Marks the field as intended for filtering; the GraphQL collection where input is generated but the resolver does not yet apply it. Full enforcement is V2. |
isSortable | Advisory in V1. Marks the field as intended for sorting; collections currently sort by updatedAt (GraphQL) — REST sorts only createdAt / updatedAt. Full enforcement is V2. |
isSensitive | Marks the field as PII. Redaction / export-exclusion is V2 behavior; in V1 it's advisory metadata. |