Thi's avatar
HomeAboutNotesBlogTopicsToolsReading
About|My sketches |Cooking |Cafe icon Support Thi
💌 [email protected]
💎

Using Github as a comment system for your site

Anh-Thi Dinh
Web DevSSGNext.jsReact
Left aside
In this note, we will explore both
utterances
and
giscus
. However, I prefer giscus.

Why choose giscus over utterances?

  • giscus is actively maintained while utterances is not.
  • giscus utilizes discussions, whereas utterances uses issues.
  • giscus supports "reply" in comments, but utterances doesn't.
  • giscus provides wrappers for popular frameworks, unlike utterances, which only uses js (requiring manual implementation, though not overly complicated).

How to use giscus

If you are using plain JS, simply follow the official guide.
For those wanting to use it with Web Frameworks like React or Vue, refer to this
giscus-component
.

Migrating from utterances

To integrate giscus into your website, follow the instructions provided in the official guide.
You can convert each issue to the corresponding discussion. Make sure what you choose in the config of Mapping between posts and discussions (giscus) or issues (utterances) is consistent. In my case, I choose "page title".
☝
Before migrating, consider creating a new discussion with the exact name you will use for the comments. Then add some comments to that discussion. After reloading your page, you should see the comments. Remember to remove this test before migrating to avoid any conflicts.
In each issue, an option "Convert to discussion" is available at the bottom right.
If you wish to convert multiple issues at once:
  1. Ensure the issues are open.
  1. Create a new label (in the label overview page — github.com/username/your-repo/labels), for example, "comments".
  1. Return to the issues page, select all the pages you want, and then add the label "comments" to them.
  1. Navigate back to the label overview page, where you will see a button "Convert to discussions" next to the label "comments".

Using utterances

Simply follow the official guide.
For integration in Next.js or in any React site, follow these steps:
  1. Create a hook
  1. Use this hook in a client component ('use client')
◆Why choose giscus over utterances?◆How to use giscus○Migrating from utterances◆Using utterances
About|My sketches |Cooking |Cafe icon Support Thi
💌 [email protected]
1import { useEffect, useState } from 'react'
2
3const useScript = (params: any) => {
4  const { url, theme, issueTerm, repo, ref } = params
5  const [status, setStatus] = useState(url ? 'loading' : 'idle')
6
7  useEffect(() => {
8    if (!url) {
9      setStatus('idle')
10      return
11    }
12
13    const script = document.createElement('script')
14    script.src = url
15    script.async = true
16    script.crossOrigin = 'anonymous'
17    script.setAttribute('theme', theme)
18    script.setAttribute('issue-term', issueTerm)
19    script.setAttribute('repo', repo)
20
21    // Check if the script is already in the document?
22    const existingScript =
23      !!document.getElementsByClassName('utterances')[0] || ref?.current?.firstChild
24
25    if (existingScript) {
26      setStatus('ready')
27    } else {
28      ref.current?.appendChild(script)
29    }
30
31    const setAttributeStatus = (event: any) => {
32      setStatus(event.type === 'load' ? 'ready' : 'error')
33    }
34
35    script.addEventListener('load', setAttributeStatus)
36    script.addEventListener('error', setAttributeStatus)
37
38    return () => {
39      if (script) {
40        script.removeEventListener('load', setAttributeStatus)
41        script.removeEventListener('error', setAttributeStatus)
42      }
43    }
44  }, [url])
45  return status
46}
47
48export default useScript
1'use client'
2
3// imports
4
5const Comments = () => {
6  const comment = useRef(null)
7
8  const status = useScript({
9    url: 'https://utteranc.es/client.js',
10    theme: 'github-light',
11    issueTerm: 'title',
12    repo: 'dinhanhthi/dinhanhthi.com-comments',
13    ref: comment
14  })
15
16  return (
17    <div className={cn(className, containerNormal, 'mt-8')}>
18      {status === 'loading' && (
19        <div>Loading comments...</div>
20      )}
21      <div ref={comment}></div>
22    </div>
23  )
24}
25
26export default Comments