2

I am attempting to copy text from a div after the URL is shortened.

I have placed a ref value in the div that will render the shortend URL. But, I am getting error:

TypeError: inputArea.input.select() is not a function.

I am not sure how to reference the text within the div.

import { useCallback, useEffect, useRef, useState } from "react";

const Shorten = () => {
        
    const [copySuccess, setCopySuccess] = useState('');
    const inputArea = useRef(null);
        
    function copyLink(e){
        inputArea.current.select();
        document.execCommand('copy');
        e.target.focus();
        setCopySuccess('Copied!');
    };
 
    {isPending && <div className="loading-text">Loading...</div>}
    {shortLink && <div ref={inputArea} className="shorten-text">{shortLink}</div>}
    <hr></hr>
    <div>
      <button className="shorten-it" onClick={copyLink} >Copy</button>
      {copySuccess}
    </div>
  </section>
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
PythonCoder1981
  • 403
  • 9
  • 19
  • [`select`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/select) function is only available for `input` or `textarea` elements. It is not available for [`div`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement). See [this answer](https://stackoverflow.com/a/48991534/2873538). – Ajeet Shah Apr 10 '21 at 09:54

1 Answers1

3

Document.execCommand will get deprecated in favor of the modern Clipboard API to interact with clipboard.

Here is how to use Clipboard API:

function updateClipboard(newClip) {
  navigator.clipboard.writeText(newClip).then(
    () => {
      setCopySuccess("Copied!");
    },
    () => {
      setCopySuccess("Copy failed!");
    }
  );
}

function copyLink() {
  navigator.permissions
    .query({ name: "clipboard-write" })
    .then((result) => {
      if (result.state === "granted" || result.state === "prompt") {
        updateClipboard(inputArea.current?.innerText);
      }
    });
}

Notes about using Clipboard API:

The Clipboard API adds greater flexibility, in that you aren't limited to copying the current selection into the clipboard, but can directly specify what information to place into the clipboard.

Using the API requires that you have the permission "clipboardRead" or "clipboardWrite" in your manifest.json file.

The clipboard-write permission is granted automatically to pages when they are in the active tab. The clipboard-read permission must be requested, which you can do by trying to read data from the clipboard.

Clipboard API (clipboard-write permission) is currently not supported by Firefox but supported by Chrome / Chromium


Or, to use Document.execCommand, you should convert the div into an input or textarea (which can be selected) and use CSS to make it look like a div:

function copyLink(e) {
  inputArea.current?.select();
  document.execCommand("copy");
  e.target.focus();
  setCopySuccess("Copied!");
}

// ...

{shortLink && (
  <input
    ref={inputArea}
    type="text"
    className="shorten-text"
    value={shortLink}
  />
)}

Or, see How to copy text from a div to clipboard if you still want to use div.

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
  • 1
    Thanks I tried the first solution and it gave me a permission error, so I updated the div to be an input field and it worked. I will need to read more on how the Clipboard API works. – PythonCoder1981 Apr 10 '21 at 15:59
  • I tested `Clipboard API` on chrome. It worked and gave me **no** permission error because write permission is automatically granted. But I think currently it is **best** to use `Document.execCommand` and later migrate to `Clipboard API` when it would be supported by more browsers. – Ajeet Shah Apr 10 '21 at 16:02
  • 1
    Ok got it I am using Firefox for development maybe the permission issue – PythonCoder1981 Apr 11 '21 at 17:13