📋 Highlight.js copy button plugin

Highlight.js is quick and easy tool to add syntax highlighting to your code blocks but one feature it lacks is a copy button to easily copy the contents of the code block.

I use Highlight.js on this website and wanted this feature to be able to quickly copy things I re-use like this regex or this env.ts file whenever I start a new project so I looked at their Plugin API and was pleasantly surprised at how easy it was to extend.

The snippet below is all you need to add a copy button to your code blocks highlighted with Highlight.js and you can test the button while copying it. 😄

hljs.addPlugin({
  "after:highlightElement": ({ el, text }) => {
    /**
     * el is the <code> element that was highlighted
     * el.parentElement is the <pre> element
     */
    const wrapper = el.parentElement;
    if (wrapper == null) {
      return;
    }

    /**
     * Make the parent relative so we can absolutely
     * position the copy button
     */
    wrapper.classList.add("relative");

    const copyButton = document.createElement("button");
    copyButton.classList.add(
      "absolute",
      "top-2",
      "right-2",
      "p-2",
      "text-gray-500",
      "hover:text-gray-700",
    );
    // Lucide copy icon
    copyButton.innerHTML = `<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>`;

    copyButton.onclick = () => {
      navigator.clipboard.writeText(text);

      // Notify user that the content has been copied
      toast.success("Copied to clipboard", {
        description: "The code block content has been copied to the clipboard.",
      });
    };

    // Append the copy button to the wrapper
    wrapper.appendChild(copyButton);
  },
});