Skip to content

Instantly share code, notes, and snippets.

@yangshun
Last active April 4, 2023 07:07
  • Star 26 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save yangshun/55db997ed0f8f4e6527571fc3bee4675 to your computer and use it in GitHub Desktop.
How to add the "Copy" button to code blocks in Docusaurus

Adding "Copy" (to Clipboard) Button

If you would like to add a button to your fenced code blocks so that users may copy the code, you can do so in Docusaurus. You will have to add some code to your Docusaurus project, as seen below.

Under static/js, create a file called code-block-buttons.js with the following:

// Turn off ESLint for this file because it's sent down to users as-is.
/* eslint-disable */
window.addEventListener('load', function() {
  function button(label, ariaLabel, icon, className) {
    const btn = document.createElement('button');
    btn.classList.add('btnIcon', className);
    btn.setAttribute('type', 'button');
    btn.setAttribute('aria-label', ariaLabel);
    btn.innerHTML =
      '<div class="btnIcon__body">' +
      icon +
      '<strong class="btnIcon__label">' +
      label +
      '</strong>' +
      '</div>';
    return btn;
  }

  function addButtons(codeBlockSelector, btn) {
    document.querySelectorAll(codeBlockSelector).forEach(function(code) {
      code.parentNode.appendChild(btn.cloneNode(true));
    });
  }

  const copyIcon =
    '<svg width="12" height="12" viewBox="340 364 14 15" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M342 375.974h4v.998h-4v-.998zm5-5.987h-5v.998h5v-.998zm2 2.994v-1.995l-3 2.993 3 2.994v-1.996h5v-1.995h-5zm-4.5-.997H342v.998h2.5v-.997zm-2.5 2.993h2.5v-.998H342v.998zm9 .998h1v1.996c-.016.28-.11.514-.297.702-.187.187-.422.28-.703.296h-10c-.547 0-1-.452-1-.998v-10.976c0-.546.453-.998 1-.998h3c0-1.107.89-1.996 2-1.996 1.11 0 2 .89 2 1.996h3c.547 0 1 .452 1 .998v4.99h-1v-2.995h-10v8.98h10v-1.996zm-9-7.983h8c0-.544-.453-.996-1-.996h-1c-.547 0-1-.453-1-.998 0-.546-.453-.998-1-.998-.547 0-1 .452-1 .998 0 .545-.453.998-1 .998h-1c-.547 0-1 .452-1 .997z" fill-rule="evenodd"/></svg>';

  addButtons(
    '.hljs',
    button('Copy', 'Copy code to clipboard', copyIcon, 'btnClipboard'),
  );

  const clipboard = new ClipboardJS('.btnClipboard', {
    target: function(trigger) {
      return trigger.parentNode.querySelector('code');
    },
  });

  clipboard.on('success', function(event) {
    event.clearSelection();
    const textEl = event.trigger.querySelector('.btnIcon__label');
    textEl.textContent = 'Copied';
    setTimeout(function() {
      textEl.textContent = 'Copy';
    }, 2000);
  });
});

Under static/css, create a file called code-block-buttons.css and add the following:

/* "Copy" code block button */
pre {
  position: relative;
}

pre .btnIcon {
  position: absolute;
  top: 4px;
  z-index: 2;
  cursor: pointer;
  border: 1px solid transparent;
  padding: 0;
  color: #fff;
  background-color: transparent;
  height: 30px;
  transition: all .25s ease-out;
}

pre .btnIcon:hover {
  text-decoration: none;
}

.btnIcon__body {
  align-items: center;
  display: flex;
}

.btnIcon svg {
  fill: currentColor;
  margin-right: .4em;
}

.btnIcon__label {
  font-size: 11px;
}

.btnClipboard {
  right: 10px;
}

Add the following to siteConfig.js:

scripts: [
  'https://buttons.github.io/buttons.js',
  'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js',
  '/js/code-block-buttons.js',
],
stylesheets: ['/css/code-block-buttons.css']

Your "Copy" to clipboard buttons should now appear at the upper right of every fenced code block.

@okraskaj
Copy link

okraskaj commented Nov 5, 2018

File names in the instructions don't match the ones in siteConfig text- it should be either code-block-buttons or code-blocks-buttons.

@yangshun
Copy link
Author

Thanks @okraskaj, I've fixed it.

@reintroducing
Copy link

it seems that adding stylesheets actually doesnt work, you get a 404 trying to load the CSS. the CSS from that file, however, does end up included in the final generated main.css, so just removing stylesheets entry from the siteConfig.js would be the right thing to do here.

@cmutagorama
Copy link

It works for me, Thanks!

@mwood23
Copy link

mwood23 commented Apr 7, 2019

For anyone that's deploying to Github pages or using a baseUrl it won't work as is. The path of the JS script needs to be the same. So you need to do something like this...

// ...
baseUrl: '/your/base/url/'
  scripts: [
    'https://buttons.github.io/buttons.js',
    'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js',
    '/your/base/url/js/code-block-buttons.js',
  ],
// ...

It also breaks if you make the path with a template string. Hope this helps someone!

@bettiolo
Copy link

This should be in the main docs

@CGick
Copy link

CGick commented Jul 23, 2019

Can this button be togglable on a per code block basis?

@joshlarsen
Copy link

it seems that adding stylesheets actually doesnt work, you get a 404 trying to load the CSS. the CSS from that file, however, does end up included in the final generated main.css, so just removing stylesheets entry from the siteConfig.js would be the right thing to do here.

@reintroducing is right, adding stylesheets: ['/css/code-block-buttons.css'] is not needed, and in fact results in a 404.

Maybe someone should update the main docs instead of relying this outdated, standalone set of instructions.

@Zenahr
Copy link

Zenahr commented Jun 22, 2020

Agreed. This should be part of the main docs.

@yangshun
Copy link
Author

yangshun commented Aug 3, 2021

Please upgrade to Docusaurus v2 instead! 😄

@steve-aerospike
Copy link

Can this button be togglable on a per code block basis?

This seems like a really good idea. Has anyone implemented it?

@yangshun
Copy link
Author

@steve-aerospike unless you're still using Docusaurus 1, this snippet is likely irrelevant.

That said, it probably can be done on a per code basis. You can add some flags or special code to your code blocks (implementation will be up to you) and customize the script to only add the copy button if the flag is not present.

@steve-aerospike
Copy link

steve-aerospike commented Feb 17, 2023

Thanks for the reply. Yes, I see now where the CodeBlock section of the Docusaurus theme has a built-in copy/paste button, and I added a new arg to suppress it as requested for certain code blocks.

@jonsveswe
Copy link

jonsveswe commented Feb 20, 2023

@steve-aerospike Hi. Did you do something like:

```js no-copy-button
let x=3;
```

Could you explain how you did it?

@steve-aerospike
Copy link

Yes, that's exactly it. I pulled out the CodeBlock/Content section from the @Docusaurus node module, and edited the file String.js. I added a noCopy arg to the CodeBlockString function definition, and edited the line which emits the copyButton to look for it.

Before editing:
<CopyButton className={styles.codeButton} code={code} />

After editing:
{!noCopy && <CopyButton className={styles.codeButton} code={code} />}

@jonsveswe
Copy link

Thanks! I swizzled the CodeBlock/Content and used the metastring inside String.js to access the attributs in the markup file. I also added an edit button using this. See https://stackoverflow.com/questions/75409516/docusaurus-add-custom-button-to-code-block

@yangshun
Copy link
Author

Please note that swizzling is a Docusaurus 2 feature while this gist is only applicable to Docusaurus 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment