Skip to content

Rendering articles (ArticleContent)

A published article’s body is plain Markdown (article.markdown). <ArticleContent> renders it to sanitized HTML — GFM on, HTML sanitized — the same contract as @ghostwritr/react and @ghostwritr/vue. It renders the result with {@html}, runs synchronously, and so works anywhere Svelte 5 runs: SvelteKit SSR, prerendered routes, and the browser (SPA).

The renderer is a separate, opt-in entry — it keeps the Markdown dependencies out of data-only consumers:

import { ArticleContent } from "@ghostwritr/svelte/article-content";

Pass the article’s markdown. With no class it renders a bare <div> wrapper; pass class to apply prose/Tailwind:

src/routes/blog/[slug]/+page.svelte
<script lang="ts">
import { ArticleHead } from "@ghostwritr/svelte";
import { ArticleContent } from "@ghostwritr/svelte/article-content";
let { data } = $props();
</script>
<ArticleHead article={data.article} siteName="Acme" />
<article>
<h1>{data.article.title}</h1>
<ArticleContent markdown={data.article.markdown} class="prose" />
</article>

The data comes from a server load that fetched the article keylessly — see the quickstart.

PropTypeDefaultEffect
markdownstring— (required)The article’s Markdown body.
classstringundefinedWrapper class on the <div> — apply prose/Tailwind here.
remarkPluginsPluggableListundefinedExtra remark plugins, appended after the built-in remark-gfm.
rehypePluginsPluggableListundefinedExtra rehype plugins, appended after the built-in rehype-sanitize.

The built-ins always apply; your plugins run after them in the same pipeline.

<ArticleContent
markdown={data.article.markdown}
class="prose"
remarkPlugins={[/* appended after remark-gfm */]}
rehypePlugins={[/* appended after rehype-sanitize — trusted */]}
/>

<ArticleContent> is a thin wrapper over renderMarkdown — the underlying synchronous Markdown → sanitized-HTML function. Reach for it directly when you need the HTML string itself (an RSS body, an email, an {@html} binding you control):

import { renderMarkdown } from "@ghostwritr/svelte/article-content";
const html = renderMarkdown(article.markdown, {
remarkPlugins: [/* appended after remark-gfm */],
rehypePlugins: [/* appended after rehype-sanitize — trusted */],
});

renderMarkdown(markdown, opts?) returns a string. It applies the same GFM + sanitize built-ins, and appends your remarkPlugins / rehypePlugins after them — identical to the component, including the post-sanitize ordering. See The article shape for what article.markdown contains.