A good[ish] website
Web development blog, loads of UI and JavaScript topics
Here’s a post that looks into how to programmatically copy text from the DOM using JavaScript. I’m going to use React as a library, but this stuff converts easily into vanilla JavaScript.
There’s two ways to go about doing this:
execCommand
method.clipBoard
interface.Although now deprecated, but still used around quit a bit, slightly hacky and clearly an archaic way of doing this. But worth knowing about.
It works like this (check out the corresponding numbers in the example code):
textarea
or in input
field.copy
command and the selected text is copied into the clipboard.Here’s the program and under is a demo for that:
import React from 'react'
const clearSelection = () => {
if (window.getSelection) window.getSelection().removeAllRanges()
}
const CopyApp = () => {
const textareaRef = React.useRef(null)
const [copyState, setCopyState] = React.useState('👈 Copy with that button')
const handleClick = () => {
if (textareaRef.current) {
textareaRef.current.focus() // 1 textareaRef.current.select() // 2
try {
const wasSuccessful = document.execCommand('copy') // 3 setCopyState(wasSuccessful ? '👍 Text copied' : 'Unable to copy')
} catch (error) {
setCopyState('Error happened')
console.log(error)
}
clearSelection() // 4 textareaRef.current.blur() // 5 }
}
return (
<div className="app">
<h1>Copy text with JavaScript</h1>
<textarea
className="textBox"
defaultValue="Heres some text that we can to copy using JavaScript."
ref={textareaRef}
/>
<button onClick={handleClick}>Copy text</button>
<span className="copy-msg">{copyState}</span>
</div>
)
}
export default CopyApp
And an execCommand
demo:
The problem with the execCommand
method is that the text needs to be in a textarea
or an input
, because it needs to be selected, because the execCommand
relies on the Document.designMode
.
If the layout requires that text is not in a textarea
or an input
field, and using this method is mandatory, in that case you can have a hidden textarea
on the page: <textarea hidden>Text</textarea>
, which holds the same content as the div
, or whatever the element is.
The clipboard API has a way more modern feel to it, of course the old browsers aren’t supported, but all the moderns ones are, so it’s not a big deal.
The clipboard method lives in the navigator: navigator.clipboard.writeText()
, and it has a writeText('foo')
method that takes a string as its parameter, which is then written into the clipboard. It returns a promise, so async
functions can be used to deal with it.
The process is much simpler:
Here’s a small React app that copies using the clipboard API:
import React from 'react'
const CopyApp = () => {
const textRef = React.useRef(null)
const [copyState, setCopyState] = React.useState('👈 Copy with that button')
const handleClick = async () => {
if (!textRef.current) return
const text = textRef.current.textContent // 1
try {
await navigator.clipboard.writeText() // 2 setCopyState('👍 Text copied')
} catch (error) {
setCopyState('🚫 Error happened')
}
}
return (
<div className="app">
<h1>Copy text with JavaScript</h1>
<div className="text-box" ref={textRef}>
Copyabe looking text!
</div>
<button onClick={handleClick}>Copy text</button>
<span className="copy-msg">{copyState}</span>
</div>
)
}
export default CopyApp
NOTE: For some reason the copy doesn’t work in the CodeSandbox frame, but it does work if you view the demo page. It just errors out with an empty Error object.
Here are all the 4 methods the clipboard
interface provides:
writeText()
write()
readText()
read()
To sun it up: writing doesn’t need permissions, reading does.
The execCommand
method works on any browser and when initiated from Iframes, and what not, but the clipboard API is the way to go!
Also, the execCommand
is deprecated, browsers probably won’t remove it any time soon, but you know, it’s on its way out.
Comments would go here, but the commenting system isn’t ready yet, sorry.