Skip to content

How to add Giscus comments to AstroPaper

Published: at 06:06 PM

If you want to skip the walk-through and see how I implemented in on this blog, check out the commit.

Hosting a thin static blog on a platform like GitHub Pages has numerous advantages, but it diminishes client-side interactivity. Fortunately, Giscus exists and offers a way to embed user comments on static sites.

Table of contents

Open Table of contents

How Giscus works

Giscus uses the GitHub API to read and store comments made by GitHub users in the Discussions associated with a repository.

Embed the Giscus client-side script bundle on your site, configure it with the correct repository URL, and users can view and write comments (when logged into GitHub)

The approach is basically serverless, as the comments are stored on GitHub and dynamically loaded from there on client side.

Setting up Giscus

Giscus can be set up easily on giscus.app, but I will outline the process shortly still.

Prequisites

Prequisites to get Giscus working are

If any of these conditions cannot be fulfilled for any reason, unfortunately, Giscus cannot be integrated.

Configuring Giscus

Next, configuring Giscus is necessary. In most cases, the preselected defaults are suitable, and you should only modify them if you have a specific reason and know what you are doing. Don’t worry too much about making the wrong choices; you can always adjust the configuration later on.

However you need to

After configuring the settings, Giscus provides you with a generated <script> tag, which you will need in the next steps.

Client-side code

You should now have a script tag that looks like this:

<script
  src="https://giscus.app/client.js"
  data-repo="[ENTER REPO HERE]"
  data-repo-id="[ENTER REPO ID HERE]"
  data-category="[ENTER CATEGORY NAME HERE]"
  data-category-id="[ENTER CATEGORY ID HERE]"
  data-mapping="pathname"
  data-strict="0"
  data-reactions-enabled="1"
  data-emit-metadata="0"
  data-input-position="bottom"
  data-theme="preferred_color_scheme"
  data-lang="en"
  crossorigin="anonymous"
  async
></script>

Simply add that to the source code of your site. For instance, if you’re using AstroPaper (the theme of this blog) and want to add comments to your posts, navigate to src/layouts/PostDetails.astro and paste it into the desired location where you want the comments to appear.

      <ShareLinks />
    </div>

+    <script src="https://giscus.app/client.js"
+        data-repo="[ENTER REPO HERE]"
+        data-repo-id="[ENTER REPO ID HERE]"
+        data-category="[ENTER CATEGORY NAME HERE]"
+        data-category-id="[ENTER CATEGORY ID HERE]"
+        data-mapping="pathname"
+        data-strict="0"
+        data-reactions-enabled="1"
+        data-emit-metadata="0"
+        data-input-position="bottom"
+        data-theme="preferred_color_scheme"
+        data-lang="en"
+        crossorigin="anonymous"
+        async>
+    </script>

  </main>
  <Footer />
</Layout>

And it’s done! You have successfully integrated comments on the blog!

Dynamic light/dark theme

The embedded script tag in the layout is quite static, with the Giscus configuration, including theme, hardcoded into the layout. Given that this blog features a light/dark theme toggle, I aimed for the comments to seamlessly transition between light and dark themes along with the rest of the site. To achieve this, a more sophisticated approach to embedding Giscus is required.

Firstly, we are going to install the React component for Giscus:

npm i @giscus/react

Then we create a new React component under src/components:

import Giscus, { type Theme } from "@giscus/react";
import { GISCUS } from "@config";
import { useEffect, useState } from "react";

interface Props {
  lightTheme?: Theme;
  darkTheme?: Theme;
}

export default function Comments({
  lightTheme = "light",
  darkTheme = "dark",
}: Props) {
  const [theme, setTheme] = useState(() => {
    const currentTheme = localStorage.getItem("theme");
    const browserTheme = window.matchMedia("(prefers-color-scheme: dark)")
      .matches
      ? "dark"
      : "light";
    return currentTheme || browserTheme;
  });

  useEffect(() => {
    const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
    const handleChange = ({ matches }: MediaQueryListEvent) => {
      setTheme(matches ? "dark" : "light");
    };

    mediaQuery.addEventListener("change", handleChange);

    return () => mediaQuery.removeEventListener("change", handleChange);
  }, []);

  useEffect(() => {
    const themeButton = document.querySelector("#theme-btn");
    const handleClick = () => {
      setTheme(prevTheme => (prevTheme === "dark" ? "light" : "dark"));
    };

    themeButton?.addEventListener("click", handleClick);

    return () => themeButton?.removeEventListener("click", handleClick);
  }, []);

  return (
    <div className="mt-8">
      <Giscus theme={theme === "light" ? lightTheme : darkTheme} {...GISCUS} />
    </div>
  );
}

EDIT (11.3.24): Thanks to benjaminrae for the tip on the proper usage of useEffect hooks.

This React component not only encompasses the Giscus comments functionality but also introduces additional props, namely lightTheme and darkTheme. Leveraging two event listeners, the Giscus comments will align with the site’s theme, dynamically switching between dark and light themes whenever the site or browser theme is changed.

To define this GISCUS config, the optimal location is in src/config.ts:

export const GISCUS: GiscusProps = {
  repo: "[ENTER REPO HERE]",
  repoId: "[ENTER REPO ID HERE]",
  category: "[ENTER CATEGORY NAME HERE]",
  categoryId: "[ENTER CATEGORY ID HERE]",
  mapping: "pathname",
  reactionsEnabled: "0",
  emitMetadata: "0",
  inputPosition: "bottom",
  lang: "en",
  loading: "lazy",
};

Note that specifying a theme here will override the lightTheme and darkTheme props, resulting in a static theme setting, similar to the previous approach of embedding Giscus with the <script> tag.

To complete the process, add the new Comments component to src/layouts/PostDetails.astro!

      <ShareLinks />
    </div>

+    <Comments client:only />

  </main>
  <Footer />
</Layout>

Feel free to test it out on this site: toggling the theme in the header bar should also switch the comments theme accordingly. If you found this tutorial helpful, don’t hesitate to leave a comment!