How to add a 'copy to clipboard' button to a code snippet in Hugo?

In this post, you'll be given a javascript code snippet to help you copy code snippets to clipboard with just a click of a button.

Share:

Apr 7, 2023 477 Words

Read Time: 3 Minutes

A screenshot of the blogpost by TnvMadhav to help you copy code to clipboard with a click of a button.

πŸ’‘ This post is a concise extract of the original post by Digital drummer J . All credits go to the original author.

You can find the original post here1 for a more detailed guide.

Javascript Code Snippet

Copy and paste this piece of code in your baseof.html or any globally defined html template in your hugo2 project:

<script>
  function createCopyButton(highlightDiv) {
    const button = document.createElement("button");
    button.className = "copy-code-button";
    button.type = "button";
    button.innerText = "Copy";
    button.addEventListener("click", () => copyCodeToClipboard(button, highlightDiv));
    highlightDiv.insertBefore(button, highlightDiv.firstChild);
  
    const wrapper = document.createElement("div");
    wrapper.className = "highlight-wrapper";
    highlightDiv.parentNode.insertBefore(wrapper, highlightDiv);
    wrapper.appendChild(highlightDiv);
  }
  
  document.querySelectorAll(".highlight").forEach((highlightDiv) => createCopyButton(highlightDiv));
  
  async function copyCodeToClipboard(button, highlightDiv) {
    const codeToCopy = highlightDiv.querySelector(":last-child > :last-child > code").innerText;
    try {
      var result = await navigator.permissions.query({ name: "clipboard-write" });
      if (result.state == "granted" || result.state == "prompt") {
        await navigator.clipboard.writeText(codeToCopy);
      } else {
        copyCodeBlockExecCommand(codeToCopy, highlightDiv);
      }
    } catch (_) {
      copyCodeBlockExecCommand(codeToCopy, highlightDiv);
    } finally {
   button.blur();
    button.innerText = "Copied!";
    setTimeout(function () {
      button.innerText = "Copy";
    }, 2000);  }
  }
  
  function copyCodeBlockExecCommand(codeToCopy, highlightDiv) {
    const textArea = document.createElement("textArea");
    textArea.contentEditable = "true";
    textArea.readOnly = "false";
    textArea.className = "copyable-text-area";
    textArea.value = codeToCopy;
    highlightDiv.insertBefore(textArea, highlightDiv.firstChild);
    const range = document.createRange();
    range.selectNodeContents(textArea);
    const sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
    textArea.setSelectionRange(0, 999999);
    document.execCommand("copy");
    highlightDiv.removeChild(textArea);
  }
  </script>

CSS Code Snippet

To beautify the button and place in the top-right corner of the code snippet tag, add this css to your style.css file in your hugo project:

.highlight-wrapper {
    display: block;
  }
  
  /* Start: Turn off individual column border, margin, and padding when line numbers are showing */
  .highlight-wrapper .lntd pre {
      padding: 0;
  }
  
  .chroma .lntd pre {
      border: 0px solid #ccc;
  }
  
  .chroma .lntd:first-child {
    padding: 7px 7px 7px 10px;
    margin: 0;
  }
  
  .chroma .lntd:last-child {
    padding: 7px 10px 7px 7px;
    margin: 0;
  }
  /* End: Turn off individual column border, margin, and padding when line numbers are showing */
  
  .highlight {
    position: relative;
    z-index: 0;
    padding: 0;
    margin:40px 0 10px 0;
    border-radius: 4px;
  }
  
  .highlight > .chroma {
    position: static;
    z-index: 1;
    border-top-left-radius: 0px;
    border-top-right-radius: 0px;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
    padding: 10px;
  }
  
  .copy-code-button {
    position: absolute;
    z-index: 2;
    right: 0;
    font-size: 13px;
    font-weight: 700;
    line-height: 14px;
    letter-spacing: 0.5px;
    width: 65px;
    color: #ffffff;
    background-color: #000000;
    border: 1.25px solid #232326;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
    border-bottom-right-radius: 0px;
    border-bottom-left-radius: 0px;
    white-space: nowrap;
    padding: 6px 6px 7px 6px;
    margin: 0 0 0 1px;
    cursor: pointer;
  }
  
  .copy-code-button:hover,
  .copy-code-button:focus,
  .copy-code-button:active,
  .copy-code-button:active:hover {
    color: #222225;
    background-color: #b3b3b3;
    opacity: 1;
  }
  
  .copyable-text-area {
    position: absolute;
    height: 0;
    z-index: -1;
    opacity: .01;
  }
  .chroma [data-lang]:before {
    position: absolute;
    z-index: 0;
    top: -29px;
    left: 0;
    content: attr(data-lang);
    font-size: 13px;
    font-weight: 700;
    color: white;
    background-color: black;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    padding: 6px 6px 7px 6px;
    line-height: 14px;
    opacity: 0.6;
    position: absolute;
    letter-spacing: 0.5px;
    border: 1.25px solid #232326;
    margin: 0 0 0 1px;
  }
  

Reference