The editor is generated from the content type. Nobody draws the form, and nobody keeps it in step: a field you add to the collection file is a field in the editor on the next boot, in the tab you put it in.
Tabs are routes
The editor’s tabs are real URLs, one segment deeper than the record:
/workspaces/:id/content/article/9c4b… General
/workspaces/:id/content/article/9c4b…/relations RelationsThe default tab is omitted from the URL, so the bare entry address stays the canonical short link — that is the one to paste to a colleague.
Tabs are routes rather than component state because the editor gets remounted by navigations it does not own. Switching locale re-targets it at the sibling record’s id, and as component state that would drop you back on General mid-task.
The properties panel
The right-hand panel holds the record’s metadata — its status, timestamps, id — and any widgets plugins contribute. On a localized type, the Locale widget lives here.
It collapses, and the collapse is remembered. When it is collapsed the reopen button moves into the top bar.
Actions
The write actions sit in the top bar, not the panel: the panel can be collapsed away entirely, and a record you cannot save is a trap.
| Action | Effect |
|---|---|
| Save draft | Stores the changes. Does not go live. |
| Save & publish | Stores, then runs the publish gate and goes live. |
| Publish | Publishes what is stored. |
| Unpublish | Takes the entry off the live site, back to draft. |
| Delete | Soft-deletes on a paranoid type, otherwise removes the record. |
The primary button changes with the record’s state, and everything is gated on
your permissions — a contributor without content:publish gets Save, not
Publish.
On a type carrying a protection rule the button also carries the approval count — 0 of 2 until the current version has been approved — and the rail grows a Review section listing who was asked and who has approved. The verdict is about the version the press would actually ship: unsaved edits are saved first, so what the button says is what the server will decide.
Saving is not publishing
On a publishable type, saving a live record moves it back to Modified: the previously published version stays live, and your changes sit on top of it as a draft. Publishing is what makes them live.
This is the single most common surprise for someone arriving from a CMS that saves straight to production, and it is deliberate. The full state table is on the content library.
Validation
The form runs the same validation rules as the server, from the same shared kernel — so the two cannot drift, and what the form accepts is what the server accepts.
On a publishable type, required fields do not block a save. They block a
publish, which is why the Publish button disables itself when the record is not
complete rather than letting you press it and fail.
If a save is refused anyway, the server’s 422 maps back onto the individual fields rather than appearing as a banner.
The busy overlay
The editor is covered for the whole write — a blur, a spinner, and “Saving…” or “Publishing…”.
It has no delay, on purpose: nothing on screen changes until the server answers, so there is nothing to hide behind a cover and a delay would only add lag. It is held across the whole flow including the refetches, so it never lifts to reveal pre-save values for a moment.
Relations
Single relations are set from a record picker in the form. Many-relations get their own control, and on a large collection they are paged rather than loading everything.
An inverse relation — the other side of a link owned by another type — is shown read-only in the places where it is derived, because editing either side moves the same rows.
Fields with their own controls
Some field types are rendered by other plugins:
richtextopens the rich-text editor.mediaopens the media library picker.- On a localized type, the locale switcher and the Translated/Shared grouping come from the localization plugin. See translating.
That is the plugin architecture showing through the interface: none of those know about the entry editor, and it does not know about them.