Add copy button to your GatsbyJS blog’s code block

Photo by Jake Walker on Unsplash

Adding code block to technical blog is a common UseCase. By using GatsbyJS, it’s quite easy. What you have to do is just install gatsby-transformer-remark and gatsby-remark-prismjs. Then modify your gatsby-config.js, add following settings like this:

But, not like gatsby-plugin-mdx, it's not easy to add copy button to code block. So, I wrote this plugin - gatsby-remark-prismjs-copy-button. Let's see how to make it work.


What we need to do is just analyze markdown ASTs which are generated by gatsby-transformer-remark, and then add copy button html before the code blocks' ASTs.

I created this plugin to make it work. It can be found here. AST

AST is the abbrev. of Abstract Syntax Tree. Before compile the source code to machine readable ones, we usually transform the human readable source code to AST first. As the tree structure is much more easier for program to operate. The famous babel, eslint, webpack, etc. are using the same mechanism. Access the following web site if you want to know more about AST.

About MarkdownAST

gatsby-transformer-remark is using markdown to transpile markdown contents to MarkdownAST. You can confirm the transpiled MarkdownAST by using the following site online.

Select both `Markdown and remark`, it'll automatically transpile the sample markdown contents. And if you click the code block in markdown side, it'll display its MarkdownAST like this.

The plugins in the options refer to the ASTs here and convert them to html for display. For example: gatsby-remark-prismjs converts all ASTs of type: "code" from code blocks to html within the pre tag. Here is the AST of the code block.

Become to this html:

How to add a copy button

So how do I add a copy button? As introduced above, the AST in the code block is not html, so you cannot easily just append the copy button html. But you can add the html part of the copy button as an AST of type: "html" before the AST of the code block, and with a few css adjustments you can move the copy button to the right place. Here is the flow.

  1. Get ASTs for all code blocks from MarkdownASTs
  2. Insert copy button’s html before the code block’s AST
  3. Adjust the position of the copy button with css (e.g. margin-top: -10px)
  4. Add the click event of copy button

So let’s begin.

Get ASTs for all code blocks from MarkdownASTs

First, you can get all MarkdownASTs from index.js in the plugin's root folder.

Then, we can get code blocks’ ASTs by filtering type: "code". We'll use unist-util-visit to do the filtering work.

Insert copy button’s html before the code block’s AST

  1. Get the original code from code block’s MarkdownAST for copy button

2. Generate copy button’s html MarkdownAST

3. Insert the generated MarkdownAST before the code block’s AST

4. Little tweaks after the insertion

As we mutate the MarkdownASTs directly(insert the copy button’s AST before code block), the node parameter in (node, index, parent) => {} will also be the processed node, so it will be an infinite loop. We must add a processed flag to node.lang and skip it.

5. Summary

To summarize the above steps, the index.js will like this:

Adjust the position of the copy button with css

  1. Add style.css

2. import style.css in gatsby-browser.js

Add the click event of copy button

Add the gatesbyRemarkCopyToClipboard function that we used when adding the copy button html MarkdownAST.


The added copy button looks like this.

And the source code.

Originally published at



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store