clubmate.fi

A good[ish] website

Web development blog, loads of UI and JavaScript topics

Copying text into the system’s clipboard with JavaScript

Filed under: JavaScript— Tagged with: textarea, click, event, react

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:

  • The execCommand method.
  • The clipBoard interface.

Copy text with the execCommand

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):

  1. Focus an element that has the text, textarea or in input field.
  2. Select the text in the field, programmatically.
  3. Execute the copy command and the selected text is copied into the clipboard.
  4. Unselect the selected text.
  5. Blur the field, as it’s now focused. This is optional.

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.

Copy text using the clipboard API

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:

  1. Grab the text from anywhere, element or API, whatever.
  2. Write it to clipboard.

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 the given string into the system’s clipboard. No permissions needed to do this.
write()
Write can white anything to the clipboard, like images. Permission is granted for the pages in the active tab.
readText()
Reads text back from the clipboard. Permissions must be granted first using the permissions api.
read()
This method reads from the clipboard. It can return any arbitrary data, not only text. Same thing with the perms.

To sun it up: writing doesn’t need permissions, reading does.

Conclusions

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. Tweet me @hiljaa if you want to make a correction etc.

  • © 2021 Antti Hiljá
  • About
  • Follow me in Twatter → @hiljaa
  • All rights reserved yadda yadda.
  • I can put just about anything here, no one reads the footer anyways.
  • I love u!