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

Find more posts from following topics

accurate-requests
api-development
api-testing
api-testing-tools
array
automated-testing
bad-habits
base64-decoder
base64-encoder
binding
blog
blogging
bulma-css
bulma.io
button-swiftui
chatgpt
clipboard
code
code-block
code-snippet
comparison
compile
configuring-debugger-for-django-in-vs-code
configuring-launch.json-for-python-debugger
copy
copy-to-clipboard
copy-to-clipboard-neovim
css
current-date
current-time
current-timestamp
debugger-setup-in-visual-studio-code
debugging-django-app-in-visual-studio-code
debugging-python-code-in-visual-studio-code
debugging-python-programs-with-visual-studio-code
debugging-python-with-virtual-environment-in-vs-code
developer-productivity
developers
development-workflow
dom
dynamic-sitemap-in-nextjs
engineering-dashboard
flowcharts
git
git-diff
github
global-keyboard-shorcut
global-shortcut
go
go-hugo
go-programming
go-to-line
golang
golang-development
good-habits
gorilla-websocket
gpt
gpt-3.5
gpt-4
gpt-4-api
guide
gumroad
habits
habits-tracker-notion-template
hamburger-menu
hotkeys
html
hugo
ide
image
image-sharing
image-tool-for-ios
imagerenderer
include-timestamp
integrated-development-environment
ios
ios-16
ios16
javascript
keyboard-shortcut
linux
macos
map
markdown
markdown-code
mental-programming
menu
menubarextra
mermaid-syntax
mistake-tracker-notion
mobile-view
modifier
navbar
navigationlink
navigationstack
neovim
next.js
nextjs
nextjs-markdown
nextjs-sitemap
nextjs-sitemaps
nice-shot
nice-shot-pro
notion
notion-api
notion-api-python
notion-budget
notion-budget-template
notion-budget-tracker
notion-bug-report-tracker
notion-dashboard
notion-expense-manager
notion-habits
notion-habits-dashboard
notion-habits-template
notion-habits-tracker
notion-habits-tracker-template
notion-issue-tracker
notion-mistake-tracker
notion-product
notion-product-dashboard
notion-product-roadmap
notion-product-roadmap-dashboard
notion-tasks
notion-tasks-dashboard
notion-tasks-template
notion-tasks-tracker
notion-template
notionworkspaces
openai
osx
personal-ifttt-framework
photospicker
photospickeritem
phpickerfilter
postman-capabilities
postman-request
pre-request-script
product-roadmap-notion-template
product-roadmap-template
productivity
programming
python
python-api
python-debugger-tutorial-for-vs-code
python-debugging-mode-in-vs-code
python-notion-api
real-time-communication
rehype
remark
request-data
running-debugger-in-visual-studio-code
running-django-app-in-debugging-mode
running-program-in-debugging-mode-in-vs-code
running-python-code-in-debugging-mode
screenshot-app-for-ios
screenshot-app-ios
screenshot-ios
screenshot-tool-for-ios
set-current-timestamp
setting-up-debugger-in-vs-code-for-python
share-extension
sharelink
sharepreview
sharesheet
simple-websocket-server
sitemap
slice
slider
step-by-step-guide
stocks-profits-tracker
stocks-profits-tracker-template
stocks-tracker
struct
sustained-vigilance
swift
swiftui
swiftui-button
swiftui-button-action
swiftui-button-style
table-of-contents
tasks-tracker-notion-template
textfield-swiftui
timeliness
timestamp-integration
transferable
triggers-and-actions
tutorial
us-stocks
usa-stocks
useful-ios-features
using-breakpoints-in-python-debugger
using-virtual-environment-with-python-debugger
vanilla-javascript
variable
vim
visual-mode
visual-studio-code
vs-code
vscode
vscode-go-to-line
web-sockets-in-go
websocket-client
websocket-programming
websocket-server
xcode