Ghost CMS: How to Add a Copy Button to Code Blocks
Want to add a copy button to code snippets in Ghost CMS? By default, Ghost doesn’t support this, but there’s a quick fix! Add a simple script to Code Injection, customize the styles, and get a handy copy button. Learn how to set it up in minutes!
Introduction
Hi! Are you looking to enhance your blog’s functionality?
By default, Ghost CMS does not provide any built-in options for quickly copying code from snippets. However, users often find this feature essential since it has long been a standard in the top-right corner of code blocks.
Forget about a copy button—Ghost CMS didn’t even support syntax highlighting for different programming languages and formats.
We’ve already covered syntax highlighting in another post:
Today, we’ll quickly add a copy button to the code snippets in your blog.
Script
I'm a lazy person, so I first did a quick search and immediately found a thread on the Ghost forum. In a reply from RyanF, it became clear that all I needed to do was add another script in the Code Injection section of my blog.
Ryan also mentioned that Prism has some kind of plugin. I found it — Copy to Clipboard Button - Prism Plugin — but I still used Ryan’s code (because it was faster).
Here’s the script you need to add to the Site Footer. By the way, I recommend using the copy button in the top-right corner right away—just click on the word html.
<script>
function initCodeCopy() {
const codeBlocks = document.querySelectorAll('code[class*="language-"]');
codeBlocks.forEach((block) => {
const lang = parseLanguage(block);
const referenceEl = block.parentElement;
const parent = block.parentElement.parentElement;
const wrapper = document.createElement('div');
wrapper.className = 'code-wrapper';
parent.insertBefore(wrapper, referenceEl);
wrapper.append(block.parentElement);
const copyBtn = document.createElement('button');
copyBtn.setAttribute('class', 'copy-button');
copyBtn.setAttribute('data-lang', lang);
copyBtn.innerHTML = `${lang} <svg viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z" fill="currentColor"/></svg>`;
wrapper.insertAdjacentElement('beforeend', copyBtn);
});
function parseLanguage(block) {
const className = block.className;
if (className.startsWith('language')) {
const [prefix, lang] = className.split('-');
return lang;
}
}
function copy(e) {
const btn = e.currentTarget;
const lang = btn.dataset.lang;
const text = e.currentTarget.previousSibling.children[0].textContent;
navigator.clipboard.writeText(text).then(
() => {
btn.innerHTML = `copied! <svg viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zm2 0h8v10h2V4H9v2z" fill="currentColor"/></svg>`;
btn.setAttribute('style', 'opacity: 1');
},
() => alert('failed to copy'),
);
setTimeout(() => {
btn.removeAttribute('style');
btn.innerHTML = `${lang} <svg viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z" fill="currentColor"/></svg>`;
}, 3000);
}
const copyButtons = document.querySelectorAll('.copy-button');
copyButtons.forEach((btn) => {
btn.addEventListener('click', copy);
});
}
document.addEventListener("DOMContentLoaded", initCodeCopy)
</script>
Styles
Keep in mind that you can easily change the colors or other display settings of the copy button.
Add the styles right after the script and modify any parameters as needed.
<style>
/* Custom styles for theme */
.code-wrapper {
position: relative;
overflow: hidden;
border-radius: 8px;
}
.code-wrapper > pre[class*="language-"] {
margin-top: 0;
}
.copy-button {
position: absolute;
top: 5px;
right: 5px;
display: flex;
align-items: center;
color: var(--ghost-accent-color);
cursor: pointer;
background: transparent;
background-color: #2d2d2d;
border: none;
}
.copy-button svg {
width: 1em;
margin-left: 0.25em;
opacity: 0.5;
transition: opacity 0.3s;
}
.copy-button:hover svg {
opacity: 1;
}
</style>
I tried to make the button look as close as possible to the one in the article A Complete Guide to Code Snippets.
After saving the changes, reload the page and start using the button!
Big thanks to RyanF for the quick solution to my problem.