Markdown body editing
CaretCMS can edit prose from Astro content collections without moving that
content into a separate database. An editor clicks the rendered paragraph or
heading, makes a change on the page, and publishes it back to the original
.md file.
Use the Markdown storage adapter. CaretCMS selects it automatically when it
finds collections under src/content/, or you can set it yourself:
import { defineConfig } from 'astro/config';import caret, { markdownStorage } from '@caretcms/core';
export default defineConfig({ integrations: [ caret({ storage: markdownStorage({ contentRoot: './src/content' }), }), ],});Markdown body editing is enabled by default. Set bodyEditing: false in
caret() if you only want frontmatter fields to be editable.
Render the entry with Astro’s normal content collection API:
---import { getEntry, render } from 'astro:content';
const post = await getEntry('blog', Astro.params.slug);if (!post) return Astro.redirect('/404');const { Content } = await render(post);---
<article class="post-body"> <Content /></article>CaretCMS adds its editing markers while Astro renders the Markdown. You do not
add data-caret to each prose block.
Editing and publishing
Section titled “Editing and publishing”- Sign in and click a marked paragraph, heading, list item, or supported paragraph inside a blockquote.
- Edit the text or use the inline formatting toolbar.
- Leave the field to save it as a private draft. The
.mdfile has not changed yet. - Use Publish to write the draft to the source file.
- Commit and deploy the source change, or use CaretCMS commit-on-publish and a rebuild webhook.
For a statically built page, visitors see the published change after the next build. A server-rendered route that reads the source at request time can show it on the next request.
Supported blocks
Section titled “Supported blocks”| Source block | Editable |
|---|---|
| Paragraph | Yes |
# ATX heading |
Yes |
| First paragraph in a list item | Yes, when its source fits on one line |
| Paragraph inside a blockquote | Yes, when its source fits on one line |
| Setext heading | No |
| Table or code block | No |
| Raw HTML block | No |
| MDX prose, JSX, or a component island | No in 0.3.0 |
Nested blocks stay read-only when their source spans more than one line. This prevents an edit from removing list indentation or blockquote markers.
Supported formatting
Section titled “Supported formatting”The toolbar can create:
- bold and emphasis;
- links.
Existing inline code round-trips safely, but 0.3 does not provide an inline-code
toolbar button. Shift+Enter can create a line break only in a top-level
paragraph; headings and nested list/quote blocks reject it so their source
structure remains intact.
CaretCMS escapes Markdown punctuation in normal text. It rejects markup outside this small set instead of guessing how to convert it.
Editing a link rewrites it as an inline Markdown link. Link titles are not kept, and a reference-style link becomes an inline link with the same text and URL.
Conflict protection
Section titled “Conflict protection”Each prose draft stores the source range and a hash of the text that was edited. CaretCMS checks that range when saving the block and checks every drafted range again before Publish. If the source changed before the block save, the editor reverts that field and asks for a reload so Astro can generate fresh stamps. If it changed after a draft was saved, Publish returns a conflict, leaves the file and draft untouched, and lets the editor reload and reapply the intent.
When an entry contains several edited blocks, CaretCMS checks all of them before writing. One stale block stops the whole entry from publishing.
Astro 6 and Astro 7
Section titled “Astro 6 and Astro 7”CaretCMS uses Astro 7’s Markdown processor when it is active and falls back to a Remark plugin for Astro 6 or another unified-based processor. Both paths produce the same editing markers and use the same source checks when publishing.
The release test suite covers both Astro versions, accented characters, emoji, Windows line endings, files without a final newline, concurrent edits, stale source ranges, history restoration, and exact preservation of unedited text.