<div class="box-center">
<!-- Copies the textContent -->
<button class="copiable">COPY ME</button>
<!-- Copies the 'data-copy-value' -->
<button class="copiable" data-copy-value="Copy this">COPY Dataset</button>
<div class="row">
<input value="I can also be copied" id="input" />
<!-- Copies the value | textContent of the target (id) -->
<button class="copiable" data-copy-target="input">Copy</button>
</div>
</div>
body {
background: #4b111b;
}
.box-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.row {
display: flex;
align-items: center;
}
button {
background: #a3243b;
border: none;
padding: 24px 40px;
color: white;
font-weight: 500;
font-size: 18px;
cursor: pointer;
border-radius: 4px;
width: 100%;
margin: 16px 0;
}
input {
background: #4B111B;
border: 2px solid #a3243b;
padding: 24px 40px;
color: white;
border-radius: 4px;
margin-right: 10px;
}
button:hover {
background-color: #f2545c;
}
.custom-toast {
background: #a3243b;
}
View Compiled
/*
* A snippet for copying to cliboard.
* - Copy from button
* - Copy from raw text
* - Copy from input
*
* Browser Support:
*
* - execCommand('copy')
* Deprecated as stated here: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand#browser_compatibility
* - Cliboard API
* Support at >90%: https://caniuse.com/mdn-api_clipboard_writetext
*
* Got some inspiration from https://stackoverflow.com/a/30810322/5900163
*
* Used in the real world:
* - Pass genny: https://pass-genny.vercel.app/
*/
/* Actual copying logic */
// Fallback in case Clipboard API is not supported
function fallbackCopyTextToClipboard(text) {
// Wrap in promise to resemble the aync Clipboard API
return new Promise((resolve, reject) => {
const textArea = document.createElement("textarea");
textArea.value = text;
// 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 {
const successful = document.execCommand("copy");
successfull ? resolve() : reject();
} catch (err) {
reject(err);
}
document.body.removeChild(textArea);
});
}
// Attempts to copy text to cliboard, either using Clipboard Async API,
// Or falling back to "execCommand('copy')"
function copyTextToClipboard(text) {
const cliboardSupported = navigator.clipboard;
const copyPromise = cliboardSupported
? navigator.clipboard.writeText(text)
: fallbackCopyTextToClipboard(text);
return copyPromise.then(() => text);
}
/* Specific case setup */
const allCopiable = document.querySelectorAll(".copiable");
allCopiable.forEach((el) => {
el.addEventListener("click", () => {
copyTextFromElement(el).then((text) => {
showToast(`Copied: "${text}"`);
}).catch((e) => {
showToast(`ERROR: "${e}"`);
});
});
});
function copyTextFromElement(element) {
const target = element.dataset["copyTarget"];
if (target) {
const targetEl = document.getElementById(target);
return copyTextToClipboard(targetEl.value ?? targetEl.textContent);
}
const text = element.dataset["copyValue"] ?? element.textContent;
return copyTextToClipboard(text);
}
// Just for demo
function showToast(message) {
Toastify({
text: message,
duration: 3000,
gravity: "top", // `top` or `bottom`
position: "center", // `left`, `center` or `right`
className: "custom-toast",
style: {
background: "#F2545C"
}
}).showToast();
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.