Images
Images, figures and uploads.
MarkdownIn Markdown
Plain Markdown, no block needed: . Alone in its paragraph with a title, it becomes a figure:
Copy code<figure>
<img src="/cat.png" alt="A cat on a sofa" loading="lazy" decoding="async" />
<figcaption>Our cat, 2026</figcaption>
</figure>Copy codeSize it with attributes so the page doesn't shift: {width="800" height="600"}. Uploads add them for you.
data:image/…URLs work, for images only.An image without a URL (
![]()) doesn't render. In the editor it's an empty card to fill.For responsive images or a CDN, replace
imgthroughcomponents, e.g.{ img: "NuxtImg" }.
In the editor
Images on their own line are cards: the picture, its caption and its alt text, edited in place. Arrowing onto a card selects it; Backspace or Delete removes it, Enter adds a paragraph after it. A card never turns back into Markdown; switch to source mode for that.
Uploads
Give the editor an upload function: it gets the File and resolves to its URL.
async function upload(file: File) {
const body = new FormData();
body.append("file", file);
const { url } = await $fetch<{ url: string }>("/api/uploads", { method: "POST", body });
return url;
}Copy codeWhile it uploads, the card shows the local file at its real size, so nothing moves when the URL arrives. Several files upload side by side, in order. A failed upload fires upload-error and removes its placeholder, or puts a replaced card back the way it was.
On the server, check what you're given: the file type by its first bytes, not its name, and a size limit. Don't accept SVG on your own origin: it can run script.
Drop, paste or choose an image:
Ready to save