Components
Components are reusable field groups. Define them once, embed them inside any content model or dynamic zone.
Why components?
Imagine a "CTA button" (label, link, style) used on twenty different pages. Modeling it as a component means you define the fields in one place, drop it into any model that needs it, and the editor experience stays consistent everywhere.
Routes
| Route | Method | Purpose |
|---|---|---|
/admin/components | GET | List components |
/admin/components/create | GET | New component form |
/admin/components | POST | Create component |
/admin/components/{component}/edit | GET | Edit component fields |
/admin/components/{component} | PUT | Update component |
/admin/components/{component} | DELETE | Delete (blocked if used anywhere) |
Component attributes
- name — display name (e.g. "CTA Block")
- slug — used to reference the component from models
- category — grouping label (Layout, Content, Marketing…)
- icon — icon shown in the dynamic-zone picker
- schema — JSON array of fields (same shape as content fields)
Embedding a component in a model
Add a field of type component on a content model and pick the component slug. On the entry form, the component renders as a nested sub-form. The stored value is a nested JSON object keyed by the component field's slug.
// Example entry data with embedded component
{
"headline": "Launch day",
"primary_cta": {
"label": "Read the post",
"url": "/blog/launch",
"style": "primary"
}
}
Dynamic zones Phase 2.5
A dynamic zone field accepts an ordered list of components chosen by the editor. The entry data records each block's component slug plus its values:
{
"blocks": [
{ "_component": "hero", "title": "…", "image": "…" },
{ "_component": "cta-block", "label": "…", "url": "…" },
{ "_component": "rich-text", "body": "…" }
]
}
Versioning
Editing a component's field schema affects all entries that embed it. Existing entries keep their stored values; missing fields fall back to defaults, and removed fields are preserved (but hidden) until the entry is re-saved.