How to add Twitter buttons to a Gatsby site

February 06, 2018

Note: this article builds upon the technique explained in my “How to Add Custom JavaScript to a Gatsby Site” article.

I recently added Twitter buttons to the bottom of each article on this site. One to share the article and one to follow my account. Because this site runs on Gatsby (and therefore React), I needed to perform a few extra steps. This article will show you exactly what to do.

Note: I used Gatsby’s starter blog, so all of my articles use a BlogPost template.

First, grab the code for the tweet button. It’ll look something like this:

<a class="twitter-share-button"
  href="https://twitter.com/intent/tweet">
Tweet</a>

Paste it somewhere in your blog post template. Next, you’ll need Twitter’s widget.js script. It looks like this:

<script>window.twttr = (function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0],
    t = window.twttr || {};
  if (d.getElementById(id)) return t;
  js = d.createElement(s);
  js.id = id;
  js.src = "https://platform.twitter.com/widgets.js";
  fjs.parentNode.insertBefore(js, fjs);

  t._e = [];
  t.ready = function(f) {
    t._e.push(f);
  };

  return t;
}(document, "script", "twitter-wjs"));</script>

We’ll need to add this to our main HTML template. But first we need to expose our html.js file:

cp .cache/default-html.js src/html.js

Since our HTML doc is embedded in JSX, we can’t just copy and paste the above Twitter script. Instead, we need to use React’s dangerouslySetInnerHTML attribute. Add the following to your HTML doc:

          <script
            dangerouslySetInnerHTML={{
              __html: `window.twttr = (function(d, s, id) {
                var js, fjs = d.getElementsByTagName(s)[0],
                  t = window.twttr || {};
                if (d.getElementById(id)) return t;
                js = d.createElement(s);
                js.id = id;
                js.src = "https://platform.twitter.com/widgets.js";
                fjs.parentNode.insertBefore(js, fjs);
              
                t._e = [];
                t.ready = function(f) {
                  t._e.push(f);
                };
              
                return t;
              }(document, "script", "twitter-wjs"));`,
            }}
          />

You should now see a share button on your blog posts. But there’s a problem! If you go to a different post without refreshing the browser, you won’t see the actual button - you’ll just see a text link. This is because the Twitter script only loads the share button when the page is first loaded. We can fix this by manually loading the button every time a post is viewed.

We’ll do this using React’s componentDidMount lifecycle method. Add the following to your blog post component:

// BlogPost.js
class BlogPostTemplate extends React.Component {
  ...
  componentDidMount() {
    if (typeof twttr.widgets !== 'undefined') {
      twttr.widgets.load()
    }
  }
  ...

This block ensures that whenever a blog post is mounted to the DOM, the Twitter widgets script is reloaded. Now if you jump around between blog posts, the button will appear on each one.

The last step is to add the follow button. Grab the code from here, it’ll look something like:

<a class="twitter-follow-button"
  href="https://twitter.com/TwitterDev">
Follow @TwitterDev</a>

Paste it anywhere in your blog post (maybe next to the share button), and refresh. It also uses the Twitter widget script we added above, so it should just work.

Since we’re working with React, you can extract both buttons to one component. Here’s what I use:

// TwitterActions.js
import React from 'react'

export default () => (
  <ul className="twitter-actions">
    <li>
      <a
        className="twitter-share-button"
        href={`https://twitter.com/intent/tweet?via=mercatante`}
        data-size="large"
      >
        Tweet
      </a>
    </li>
    <li>
      <a
        className="twitter-follow-button"
        href="https://twitter.com/mercatante"
        data-show-count="false"
        data-size="large"
      >
        Follow @mercatante
      </a>
    </li>
  </ul>
)

Hi, I'm Steven Mercatante.
I build awesome things for the web using Python, JavaScript and Elixir.
Contact me if you'd like to work together.