How to add comment support on your Gatsby blog using Github utterances
Tags: gatsby, blog, comments, utterances
Published: 2020-07-29 08:21:58

---
title: "How to add comment support on your Gatsby blog using Github utterances"
published: true
description: "Utterances is a free and opensource comments service powered by Github"
tags: ["gatsbyjs", "blog", "comments", "utterances"]
cover_image: "https://images.unsplash.com/photo-1516414447565-b14be0adf13e"
---

Originally posted on my blog: [creativcoder.dev](https://creativcoder.dev/how-to-add-github-utterances-blog)

This post is about integrating comments support in your blog using a free and open source service.

Having a way to engage with your audience is probably the next step you can take if your blog is helping others in some way. Back when I had used [hugo](https://gohugo.io/) as my static site generator, I had used [Disqus](https://disqus.com/), which is a comments service/system. But as with ordinary third party services, Disqus is notorious for putting their own ads and can get quite slow. As a fan of open source and code reuse, I knew there had to be some open source comments service out there. After a day of sifting through the interwebs, I found a solution that I think for the time being serves my purpose of engaging with my audience.

What follows is a quick guide on how to integrate Github's [utterances](https://github.com/utterance) comments system into your blog. This also became an excuse for me stay updated with all the recent changes in the web dev space, as I've been mostly doing backend for the last two years.

Utternaces is a lightweight comments widget built on top of Github issues. Some of its highlights are:

* Open source. 🙌

* No tracking, no ads, always free. 📡

* No lock-in. All data stored in GitHub issues. 🔓

* Styled with Primer, the css toolkit that powers GitHub. 💅

* Dark theme. 🌘

* Lightweight. Vanilla TypeScript. No font downloads, JavaScript frameworks or polyfills for evergreen browsers. 🐦🌲

---

**Target audience**: You know ReactJS, and you probably know better than me and maybe can provide suggestions on how can we improve the integration.

**Disclaimer**: This comments system only works if your target audience has a Github account, which in majority of cases are developers. As my blog is mostly oriented towards developers, this aligns perfectly with my blog.

---

The official guide of [utterances](https://utteranc.es/) mentions integrating the comments widget on a vanilla HTML website. That won't work for my case as I happen to be running a site that is generated by [GatsbyJS](https://www.gatsbyjs.org/), which I think is a really efficient static site generator not only in terms of development experience but also in terms of performance of the generated sites compared to my past experiences with static site generators such as Hugo.

Gatsby uses React under the hood which meant that I needed to integrate utterances as a [React component](https://reactjs.org/docs/components-and-props.html). 

*Note*: I am by no means an expert on react or even a frontend expert, but the following steps
is me just sifting through bunch of documentation pages and tying to cobble them together into
a working solution.

So here's how I did it.

## Installing utterances

First, I setup a Github repository (has to be a public repository) that will act
as a placeholder for issues to be created within: https://github.com/creativcoder/creativcoder.dev-comments
This is needed if you have a website that is not running as a Github pages site. If you happen to have your website as a Github repository, you can configure the same repository for utterances.

Next, we go to: https://github.com/apps/utterances page. You will see an 'Install' button in green on the right. Clicking that, you will need to provide the repository where you want to install the widget. I chose my comments repository above.

Post installation, you will be redirected to this [page](https://utteranc.es/). In the 'Enabling Utterances' section, we need to place the following script in a div tag (or any container tag) where we want our comment widget to appear:

```html
<script src="https://utteranc.es/client.js"
        repo="[ENTER REPO HERE]"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async>
</script>
```

As you can see, the script tag above has multiple attributes that can be configured. The important ones to look at are:

* `repo`: should point to the repository you installed utterances above section.
* `issue-term`: how utterances should match the issues with posts on a website. In my case, am using the title of the posts. You can refer to 'Blog Post <-> Issue Mapping' section in https://utteranc.es/ for more details and choose as per your preference.

## Integrating the comment widget

Now as I said above, the script needs to be put in a container tag for us to render the comments widget. That translates to having a component in react, within which we'll append this script tag programmatically whenever a blog post page is rendered. This will need to happen conditionally as not all pages are about a blog post page, such as the index page and the about page.

To have a container for the widget to be created within, I first created a `Comment` react component ([a functional component](https://www.robinwieruch.de/react-function-component)) in `components/comment.js`: 

```jsx
// commment.js

import {useRef, useEffect} from 'react'
import React from 'react';
import { useStaticQuery, graphql } from 'gatsby'

const Comment = ({commentBox}) => (<div ref={commentBox} className="comments"></div>)
export default Comment

```

It's a very trivial component. The only thing of intereset here is the `commentBox` react ref. [React Refs](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) provide a way to access DOM nodes or React elements created within a component's render method. We'll see how that is used later. It's not really recommended to use refs, as they are sort of an escape hatch but since we only have one use case for it here, we should be fine.

Next, I have a `<Posts>` component in my blog which renders each blog post. This is where I want the comment widget to appear at the end of each post. I needed a way to render the `Comments` component conditionally. To achieve that, I relied on the `excerpt` prop which is `true` if the rendered page is an index page, where only an excerpt of all blog posts are shown. In other cases it's set to `false`. We can use that to conditionally render the `Comments` component like so:

```jsx
// components/posts.js
{ excerpt? <></>: <Comment commentBox={commentBox} />}
```

It's the usual ternary operator. The `<></>` syntax are [fragments](https://reactjs.org/docs/fragments.html) in react, which is empty in the true branch as we only want to render the widget when the user in on the blog post page. We also see that the comment widget has a `commentBox` prop being passed. This is how we gain access to the `Comment` component for use within the `Posts` component. We'll use this ref to append the comment script tag.

Back in my `Posts` component, I create a ref that was attached to the `commentBox` prop on `Comment` component:

```jsx
// components/post.js
const commentBox = React.createRef()
```

Then, I use the `useEffect` hook to add the script tag to the `Comment` component via the ref:

```jsx
  const commentBox = React.createRef()

  useEffect(() => {
    const scriptEl = document.createElement('script')
    scriptEl.async = true
    scriptEl.src = 'https://utteranc.es/client.js'
    scriptEl.setAttribute('repo', 'creativcoder/creativcoder.dev-comments')
    scriptEl.setAttribute('issue-term', 'title')
    scriptEl.setAttribute('id', 'utterances')
    scriptEl.setAttribute('theme', 'github-light')
    scriptEl.setAttribute('crossorigin', 'anonymous')
    if (commentBox && commentBox.current) {
      commentBox.current.appendChild(scriptEl)
    } else {
      console.log(`Error adding utterances comments on: ${commentBox}`)
    }
  }, [])
```

The code in `useEffect` will run everytime a `Post` component is rendered which will then append the comment widget to each blog post page. You can see that set the same script attributes are being added but with javascript. We then finally append it to the `commentBox` ref via its `current` property which is active when it is rendered.

With that done, I did just did a `yarn deploy` and what you see below is our shiny new comment widget 👇.
Hope you find this post helpful. Let me know if you have any issues setting it up in the comments below.

Until next time!