Copy text to clipboard: Cannot read properties of undefined reading 'writeText'
Asked Answered
C

4

63

I have a button

enter image description here

When I clicked on COPY

copyImageLinkText({ mouseenter, mouseleave }, e) {
  this.showCopiedText = !this.showCopiedText
  navigator.clipboard.writeText(this.imageLink)

  clearTimeout(this._timerId)
  mouseenter(e)
  this._timerId = setTimeout(() => mouseleave(e), 1000)
},

This line seems to work perfectly locally on my MacBook Pro

navigator.clipboard.writeText(this.imageLink)

It's not working when I build and deployed it to my dev server.

TypeError: Cannot read properties of undefined (reading 'writeText')

enter image description here

Contiguous answered 14/4, 2022 at 15:10 Comment(0)
G
140

The use of navigator.clipboard requires a secure origin. So if your dev environment is being served over HTTP, then the clipboard method won't be available.

According to MDN Clipboard docs

This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

Maybe you could check if this method is available with window.isSecureContext, and disable the Copy Text button accordingly.


Workaround

The best option is to use HTTPS in your dev environment.

But since you asked for a workaround, here's a (very hacky) working method. Using Document.exec command, which is no longer recommended, in favour of ClipboardAPI.

function unsecuredCopyToClipboard(text) {
  const textArea = document.createElement("textarea");
  textArea.value = text;
  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();
  try {
    document.execCommand('copy');
  } catch (err) {
    console.error('Unable to copy to clipboard', err);
  }
  document.body.removeChild(textArea);
}

Usage

You can then just check if !navigator.clipboard and call the fallback method, otherwise continue with the normal navigator.clipboard.writeText(...) function. For example:

const unsecuredCopyToClipboard = (text) => { const textArea = document.createElement("textarea"); textArea.value=text; document.body.appendChild(textArea); textArea.focus();textArea.select(); try{document.execCommand('copy')}catch(err){console.error('Unable to copy to clipboard',err)}document.body.removeChild(textArea)};

/**
 * Copies the text passed as param to the system clipboard
 * Check if using HTTPS and navigator.clipboard is available
 * Then uses standard clipboard API, otherwise uses fallback
*/
const copyToClipboard = (content) => {
  if (window.isSecureContext && navigator.clipboard) {
    navigator.clipboard.writeText(content);
  } else {
    unsecuredCopyToClipboard(content);
  }
};
<button onClick="buttonPress()">➡️ Copy Message to Clipboard</button>

<script type="text/javascript"> const buttonPress = () => { copyToClipboard('Hello World!'); console.log('Clipboard updated 📥\nNow try pasting!'); }; </script>
Geek answered 14/4, 2022 at 18:37 Comment(4)
how then navigator.clipboard works on localhost that has http?Nordgren
@Nordgren Locally-delivered resources are also considered secure, as there's no opportunity for an external actor to use a MITM attack :) See the When is a context considered secure? section in the MDN docs for more info.Geek
Upvote for the Information about it will only work with SSLJinnyjinrikisha
document.execCommand is deprecated.Fidelafidelas
A
3

Some addition for the answer, that was useful for me, scroll with preventScroll parameter as an argument for the scroll func, since the input will be removed, you probable won't need scroll to it

 textArea.focus({preventScroll: true})
Attempt answered 12/4, 2023 at 20:22 Comment(0)
C
2

It is better to use an async and put your code in try catch block.

async function copyCode() {
 try {
     await navigator.clipboard.writeText(this.input);
 } catch (e) {
     console.log(e);
 }
}
Caffeine answered 28/5, 2022 at 12:38 Comment(0)
Y
0

Sorry for pasting a working code. I am using Jquery. you can do with JS only if you wish. It will not work until over https view..

$('.copy-email').click(function () {
    var email = $(this).data('email');
    writeClipboardText(email);
})

async function writeClipboardText(text) {
    try {
        await navigator.clipboard.writeText(text);
    } catch (error) {
        console.error(error.message);
    }
}
Yeargain answered 8/4, 2024 at 9:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.