Using Remark42 in Astro (w/Svelte Components)
Astro is an all-in-one web framework for building fast, content-focused websites.
- Content-focused: Astro was designed for content-rich websites.
- Server-first: Websites run faster when they render HTML on the server.
- Fast by default: It should be impossible to build a slow website in Astro.
- Easy to use: You don't need to be an expert to build something with Astro.
- Fully-featured, but flexible: Over 100+ Astro integrations to choose from.
While Astro supports numerous front-end framework integrations (e.g. React, Vue, SolidJS, etc.) this integration implements Svelte components and Astro's islands architecture for partial hydration.
Svelte Component (Embedded Frame)
remark42-embed.svelte
<svelte:head>
<script async lang="javascript">
var remark_config = {
host: "https://your.website.here",
site_id: "yourwebsite",
components: ["embed"],
show_rss_subsription: false,
theme: localStorage.getItem("color-theme") ?? "light",
};
!(function (e, n) {
for (var o = 0; o < e.length; o++) {
var r = n.createElement("script"),
c = ".js",
d = n.head || n.body;
"noModule" in r ? ((r.type = "module"), (c = ".mjs")) : (r.async = !0),
(r.defer = !0),
(r.src = remark_config.host + "/web/" + e[o] + c),
d.appendChild(r);
}
})(remark_config.components || ["embed"], document);
</script>
</svelte:head>
<div id="remark42" />
Astro Layout (Page)
blogpageLayout.astro (partial Astro layout)
---
...
import Remark42Embed from "../components/remark42-embed.svelte";
export interface Props {
frontmatter: Frontmatter;
}
const { frontmatter } = Astro.props;
---
<html lang="en">
...
<article class="markdown">
<slot />
</article>
{frontmatter.comments && <Remark42Embed client:visible />}
...
</html>
Note the use of the client:visible
directive which will hydrate the component once the element becomes visible.
Svelte Component (Counter)
remark42-counter.svelte
<script>
export let url;
</script>
<svelte:head>
<script async lang="javascript">
var remark_config = {
host: "https://your.website.here",
site_id: "yourwebsite",
components: ["counter"],
show_rss_subsription: false,
theme: localStorage.getItem("color-theme") ?? "light",
};
!(function (e, n) {
for (var o = 0; o < e.length; o++) {
var r = n.createElement("script"),
c = ".js",
d = n.head || n.body;
"noModule" in r ? ((r.type = "module"), (c = ".mjs")) : (r.async = !0),
(r.defer = !0),
(r.src = remark_config.host + "/web/" + e[o] + c),
d.appendChild(r);
}
})(remark_config.components || ["embed"], document);
</script>
</svelte:head>
<span class="remark42__counter" data-url={url.href} />
Astro Component (Card)
blogCard.astro (partial Astro component)
---
const { post } = Astro.props;
import Remark42Count from "../components/remark42-count.svelte";
...
---
<div>
...
<!-- Read Time & Comment Count -->
{
post.frontmatter.comments && (
<div class="my-2 text-center font-Roboto font-light text-gray-600 dark:text-gray-300">
{post.frontmatter.minutes} minutes •
<Remark42Count url={new URL(post.url, Astro.site)} client:idle /> comments
</div>
)
}
...
</div>
Note the use of the client:idle
directive which will hydrate the component once the page has completed the initial load.