Copy Clipboard with Prism

calculating....


  1. html
  2. css
  3. JavaScript

In web development, a copy clipboard feature is a simple but powerful tool that enhances user experience. It allows users to copy text to their clipboard with just a click of a button, saving them time and effort. In this tutorial, we will walk through how to create a copy clipboard using CSS, and JavaScript.

copy-clipboard-with-prism

What You Will Learn:

  • How to create a copy-to-clipboard input field with a button 🖥️
  • Styling the copy with modern CSS effects for a smooth, interactive UI 🎨
  • Using the JavaScript Clipboard to copy code to the clipboard 📋
  • Adding an animation for visual feedback when code is copied ✨
  • Customizing the design to suit different themes and UI styles🎯

Add Prism via Code Injection

To function, PrismJS requires JavaScript and CSS. The JS parses your code blocks and the CSS styles theme.

PrismJS offers several color themes. Choose the theme you want to use and load its CSS. In the code below, we use the default theme.

✔️ Copy or Download the exact code block design width - PrismJS

With the Prism recommends using their autoloader script, which automatically loads the needed languages.

Add the snippet below to Settings Code injection Site header:

<script src="https://cdn.jsdelivr.net/npm/prismjs/prism.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/autoloader/prism-autoloader.min.js" defer></script>

However, if you wanted to use the Twilight theme, change the filename from prism.min.css to prism-twilight.min.css.

Again, add the following code to Code injection Site header:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs/themes/prism.min.css">

Add CSS Styling

Now, let’s make the button and input field visually appealing. The CSS will also include an animation effect that will notify the user when the text has been copied.

.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: rgb(230 202 168);
    cursor: pointer;
    background: transparent;
    background-color: #011627;
    border: none;
}

.copy-button svg {
    width: 1em;
    margin-left: 0.25em;
    opacity: 0.5;
    transition: opacity 0.3s;
}

.copy-button:hover svg {
    opacity: 1;
}

Add JavaScript for Copying Functionality

Now comes the core functionality! We’ll use the Clipboard to copy the text from the input field when the user clicks the “Copy” button.

Now, let’s make the button and input field visually appealing. The CSS will also include an animation effect that will notify the user when the text has been copied.

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;
  }
}

        async function fallbackCopyTextToClipboard(text) {
            return new Promise((resolve, reject) => {
                var textArea = document.createElement('textarea');
                textArea.value = copyInfo.getText();
                // Avoid scrolling to bottom
                textArea.style.top = '0';
                textArea.style.left = '0';
            textArea.style.position = 'fixed';
                document.body.appendChild(textArea);
            textArea.focus();
                textArea.select();
                try {
                    var successful = document.execCommand('copy');
                    setTimeout(function () {
                    if (successful) {
                            resolve('success')
                        } else {
                            reject('error')
                        }
                    }, 1);
                } catch (err) {
                    setTimeout(function () {
                        reject(err)
                    }, 1);
                } finally {
                    document.body.removeChild(textArea);
                }
        })
        }
                                 
        async function copyTextToClipboard(text) {
            return new Promise((resolve, reject) => {
                if (navigator.clipboard) {
                navigator.clipboard.writeText(text).then(
                        resolve(), function () {
                    // try the fallback in case `writeText` didn't work
                        fallbackCopyTextToClipboard(text).then(
                            () => resolve(),
                            () => reject()
                        )
                    });
            } else {
                fallbackCopyTextToClipboard(text).then(
                    () => resolve(),
                        () => reject()
                    )
                }
            })
    }

function copy(e) {
        const btn = e.currentTarget;
        const lang = btn.dataset.lang;
    const text = e.currentTarget.previousSibling.children[0].textContent;
    copyTextToClipboard(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);
    });
    }
    initCodeCopy()

🐘 If you found this tutorial helpful, don’t forget to like Dervic Blog's, or subscribe my RSS for more exciting web development tutorials!


Comments (0)

Thank you!