Skip to main content
Version: 0.3.36

Elements

An Element type is a reusable content block: a named set of fields such as a hero banner, a text block or a quote. An element is an instance of that type stored inside a node's properties. Element types are what an Archetype lists in a SectionField, so editors can compose a page from blocks while the server validates each block against its type.

Element types and archetypes share one field schema. This page is the reference for both.

An element type

name: arch:Hero
title: Hero
fields:
- $type: TextField
name: heading
title: Heading
required: true
translatable: true
config:
max_length: 120
- $type: MediaField
name: image
- $type: OptionsField
name: align
config:
options: [left, center]
render_as: Radio
FieldTypeMeaning
namestringIdentifier, conventionally namespace:Name
extendsstringParent element type; fields merge by name, child wins, 20 levels maximum
title, description, iconstringEditor labels
fieldsarrayThe field schemas below. Defaults to an empty list
layoutarrayOptional layout tree for the editor (same format as archetypes)
strictboolWhen true, an element may only contain keys named in the resolved fields
publishableboolSet by publishing. Not required for the type to be used
initial_content, metaobjectStored and returned untouched

Created with POST /api/management/{repo}/{branch}/elementtypes and a {"element_type": {...}} body, or as package/elementtypes/<name>.yaml in a package. The response is the stored record:

{"id":"3tPiu1sfNV89jWlU","name":"arch:Hero","title":"Hero","description":null,
"fields":[{"$type":"TextField","name":"heading","title":"Heading","required":true,"translatable":true,"config":{"max_length":120}},
{"$type":"MediaField","name":"image"},
{"$type":"OptionsField","name":"align","config":{"options":["left","center"],"render_as":"Radio"}}],
"version":1,"created_at":"2026-09-06T18:37:57.033632Z","updated_at":"2026-09-06T18:37:57.033632Z",
"published_at":null,"published_by":null,"publishable":null,"previous_version":null}

An element in a node

An element is a JSON object with an element_type key, an optional uuid, and the field values at the top level:

{
"name": "spring",
"node_type": "blog:Article",
"archetype": "arch:LandingPage",
"properties": {
"title": "Spring sale",
"sections": [
{ "element_type": "arch:Hero", "uuid": "hero-1", "heading": "Welcome", "align": "center" },
{ "element_type": "arch:TextBlock", "body": "<p>Hi</p>" }
]
}
}

The server stores the object as written and returns it in the same shape. A nested {"element_type": "...", "content": {...}} form is also accepted on input. uuid is optional in general; it becomes mandatory for items of a repeatable composite that has translatable sub-fields, because the translation overlay addresses items by uuid (see Translations).

Elements can appear anywhere in properties, not only under an archetype field. On every write the validator walks all property values, and any object with an element_type is checked against that element type. An unknown type is an error:

{"code":"VALIDATION_FAILED","message":"Failed to resolve element type 'nope:X': Not found: ElementType not found: nope:X (at element 'nope:X', path 'blocks[0]')"}

Field schemas

Every field is an object tagged with $type. All types share the base keys; some add a config object.

Base keys

KeyTypeMeaning
namestringProperty key in the stored content
title, label, description, help_textstringEditor text
requiredboolEnforced on write
default_valueanyEditor default. Not applied by the server
multipleboolRepeatable. Enforced for ElementField; the uuid rule above applies to CompositeField
translatableboolThe field takes part in translation overlays
is_hidden, design_valueboolEditor hints
validationsarray of stringsStored for clients; not evaluated by the server
indexarrayFulltext, Vector, Property
encryptedboolValue is moved to the secret store on write and read back as a secret:// reference
metamapFree-form, stored untouched

Types

$typeconfig keysNotes
TextFieldmax_length
RichTextFieldmax_length
NumberFieldis_integer, min_value, max_value
DateFielddate_format, date_mode (DateTime, Date, Time)
BooleanField
LocationField
MediaFieldallowed_types
ReferenceFieldallowed_entry_types
TagFieldallowed_tags, max_tags
OptionsFieldoptions, render_as (Dropdown, Radio, Checkbox), multi_select
JsonObjectFieldArbitrary JSON
ListingFieldallowed_entry_types, sort_by, sort_order, limit
CompositeFieldHas its own fields and optional layout; an inline group with no separate type
ElementFieldelement_type names the one type allowed; the value is a single element, or a list when multiple
SectionFieldallowed_element_types lists the types allowed in the list; render_as is an editor hint

config values are editor hints. The server enforces required, strict, the type checks on ElementField and SectionField, and the uuid rule for translatable composites. It does not check lengths, ranges or option membership.

Layout

layout is a list of layout nodes, tagged by type:

layout:
- type: container
direction: Vertical # or Horizontal
spacing: 8
alignment: Leading # Leading, Center, Trailing
children:
- type: field
name: heading
- type: group
label: Appearance
children:
- type: field
name: image
width: 50%
- type: field
name: align
condition:
field: image
operator: NotEquals # Equals, NotEquals, GreaterThan, LessThan, Contains
value: null
- type: tab_panel
tabs:
- name: Advanced
children:
- type: field
name: cta
- type: grid
rows: 1
columns: 2
children: []

The layout is stored and returned as-is; rendering it is the editor's job.

Inheritance and the resolved view

GET /api/management/{repo}/{branch}/elementtypes/{name}/resolved returns the type with its extends chain merged:

{
"element_type": { "name": "arch:Hero", "fields": [ ... ], "version": 2, "publishable": true },
"resolved_fields": [
{ "$type": "OptionsField", "name": "align", "config": { "options": ["left", "center"], "render_as": "Radio" } },
{ "$type": "TextField", "name": "heading", "title": "Heading", "required": true, "translatable": true, "config": { "max_length": 120 } },
{ "$type": "MediaField", "name": "image" }
],
"resolved_layout": null,
"inheritance_chain": ["arch:Hero"],
"resolved_strict": false
}

resolved_fields is sorted by name. The JavaScript client has db.elementTypes().getResolved(name); schemas are per branch, so use db.onBranch('staging') to resolve elsewhere.

Strict element types

With strict: true on the type, an element carrying a key that is not a resolved field is rejected:

{"code":"VALIDATION_FAILED","message":"Undefined property 'extra' in strict element type 'arch:TextBlock' at path 'archetype 'arch:LandingPage'.sections[0]'"}

SQL

CREATE ELEMENTTYPE 'arch:Quote' DESCRIPTION 'A quote' FIELDS (text String REQUIRED) creates the record with its fields, ALTER ELEMENTTYPE ... ADD FIELD / DROP FIELD / MODIFY FIELD changes them, and DROP ELEMENTTYPE 'arch:Quote' removes it. Which element types a SectionField accepts still needs HTTP, the client or YAML. See DDL.

Next steps