Browsing content
Each content type has a paginated document table at/admin/content/:type. The table includes:
| Column | Description |
|---|---|
| Title / Path | Document title from frontmatter, with the filesystem path below it |
| Translations | Locale coverage summary (only for localized types, e.g., “2/4 locales”) |
| Status | Published, Draft, or Changed (published with unpublished edits) |
| Updated | Relative timestamp (e.g., “5 min ago”, “Yesterday”) |
| Author | Avatar and initials of the creator |
- Server-side search — Debounced text search across document titles and paths
- Status filter — All, Published, Draft only, Has changes
- Sort order — Last updated, Created, Path A-Z, Path Z-A
- Pagination — Server-side with page navigation controls
Creating a document
Navigate to the content type
Go to Content in the sidebar, then select the type you want to create a
document for (e.g.,
BlogPost).Click New Document
Click the New Document button in the top-right corner. A dialog appears
asking for the document path and, for localized types, the locale.
Fill in the path
Enter a path relative to the type’s content directory (e.g.,
my-first-post.mdx). For localized types, select the target locale.Edit frontmatter
In the right sidebar under the Fields tab, fill in schema-driven
frontmatter fields. Required fields are marked with an asterisk.
Write the body
Use the TipTap-based MDX editor on the left panel to write your document
content. The editor supports standard Markdown formatting and MDX component
insertion.
Editor layout
The document editor at/admin/content/:type/:documentId uses a two-panel layout:
- Left panel — TipTap rich text editor for the document body. Supports Markdown formatting, headings, lists, code blocks, and MDX component insertion.
- Right sidebar — Tabbed panel with:
- Fields — Schema-driven frontmatter form with type-appropriate controls
- Info — Read-only document metadata (document ID, translation group ID, path, schema type, content format, locale, status, published version, draft revision, created by, last updated by)
- SEO — Coming soon (disabled tab)
Frontmatter editing
The Fields tab generates form controls based on your schema field definitions. Each Zod type maps to a specific UI control:| Schema type | Form control | Notes |
|---|---|---|
z.string() | Text input | Supports .min() / .max() validation |
z.number() | Number input | |
z.boolean() | Toggle switch | |
z.enum([...]) | Dropdown select | Options derived from enum values |
z.coerce.date() | Date picker | Calendar popover with formatted display |
z.array(z.string()) | Tag input | Type and press Enter to add tags; click to remove |
reference("Type") | Document picker | Select from existing documents of the referenced type |
What about unsupported types?
What about unsupported types?
Complex or nested Zod types that don’t map to a standard control display a
“Not editable yet” message in the form. The underlying data is preserved — it
won’t be lost if you save the document. This ensures forward compatibility as
more field types gain UI support.
min, max, regex) are displayed inline below the field.
MDX components
If yourmdcms.config.ts registers MDX components, you can insert them directly in the editor.
Insertion methods
There are two ways to insert a component:- Slash command — Type
/in an empty line to open the component picker. Search by name and select a component. - Toolbar action — Click the Insert Component button in the editor toolbar to browse the full component catalog.
components array.
Component types
- Void components — Render as self-closing tags (
<Banner />) with no nested content - Wrapper components — Render with opening/closing tags (
<Callout>...</Callout>) and support nested rich text content inside the node view
Props editing
When you select an MDX component node in the editor, the sidebar props panel activates. Props editing follows this resolution order:- Custom editor — If the component registration includes a
loadPropsEditor, it loads asynchronously and provides a fully custom editing experience - Auto-form — If no custom editor exists but the component has extracted props metadata, an auto-generated form is shown. For wrapper components, the
childrenprop is excluded since it’s edited inline. - Empty — Components with no editable props show an empty state
The component catalog is sourced from your local
mdcms.config.ts, not from
the server. No backend component sync is required. The server only needs to
know about your content schema.Auto-save
Draft changes are saved automatically using a debounced strategy:- Changes trigger a save after approximately 5 seconds of inactivity
- Saving also fires immediately when the editor loses focus (blur event)
- The save status is shown in the editor UI:
- Unsaved — Changes pending
- Saving — Write request in flight
- Saved — Draft persisted successfully
draftRevision counter on the document. Auto-saves do not create version history entries — only explicit publishes do.
The save operation uses PUT /api/v1/content/:documentId and includes the active environment’s schema hash for conflict detection. If the schema has drifted (e.g., someone ran mdcms schema sync with a different schema), the editor switches to read-only mode and shows a schema recovery prompt.