Last updated: Mar 7, 2024
Reading timeยท6 min
The navigator.clipboard
object might be undefined
because the Clipboard
API is only available in secure contexts (HTTPS).
You can resolve the issue in multiple ways:
document.execCommand
if navigator.clipboard
is
undefined
.As shown in this section of the MDN docs, the Clipboard API is only available in secure contexts (HTTPS).
If you try to use the API using the HTTP protocol, then navigator.clipboard
will be undefined
and you will likely get one of the following errors:
You can use the window.isSecureContext property if you need to check if your code is run in a secure context.
The property returns true
if the context is secure and false
otherwise.
console.log(window.isSecureContext); if (window.isSecureContext) { console.log( 'The context is secure, can use navigator.clipboard', ); } else { console.log('The context is NOT secure'); }
One way to get around the issue is to enable the "Insecure origins treated as secure" setting:
Enter chrome://flags
in your browser's address bar.
Search for Insecure origins treated as secure.
Enable the setting by clicking on the button to the right.
Type the origins that you want to enable the setting for, e.g.
http://localhost:3000
or http://example.com
.
http://localhost:3000,http://example.com
http://
or https://
).Suppose you have the following HTML.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <body> <div class="box">bobbyhadz.com</div> <div id="content">Some text to copy here</div> <button id="btn">Copy text</button> <script src="index.js"></script> </body> </html>
Here is the code for the index.js
file.
const button = document.getElementById('btn'); const contentDiv = document.getElementById('content'); button.addEventListener('click', async () => { console.log(navigator.clipboard); await navigator.clipboard.writeText(contentDiv.innerText); console.log('Copied!') });
The code sample works after making the change and enables me to copy the text without using HTTPS.
Note that the writeText()
method returns a Promise, therefore you either have
to await
it or use the .then()
syntax.
Here is an example that uses the then() syntax instead.
const button = document.getElementById('btn'); const contentDiv = document.getElementById('content'); button.addEventListener('click', () => { console.log(navigator.clipboard); navigator.clipboard .writeText(contentDiv.innerText) .then(() => { console.log('The text has been copied'); }); });
The callback function we passed to .then()
gets called after the Promise has
been resolved.
navigator.clipboard
is undefinedAn alternative approach to resolve the issue with navigator.clipboard
being
undefined
is to provide a fallback using document.execCommand
.
Here is the HTML for the example.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <body> <div class="box">bobbyhadz.com</div> <button id="btn">Copy text</button> <script src="index.js"></script> </body> </html>
And here is the related JavaScript code.
const button = document.getElementById('btn'); button.addEventListener('click', async () => { try { await copyToClipboard('The text you want to copy ๐'); console.log('Copied!'); } catch (err) { console.log(err); } }); /** * Universal copyToClipboard function */ async function copyToClipboard(textToCopy) { if (navigator.clipboard && window.isSecureContext) { await navigator.clipboard.writeText(textToCopy); } else { const textarea = document.createElement('textarea'); textarea.value = textToCopy; // Move the textarea outside the viewport to make it invisible textarea.style.position = 'absolute'; textarea.style.left = '-99999999px'; document.body.prepend(textarea); // highlight the content of the textarea element textarea.select(); try { document.execCommand('copy'); } catch (err) { console.log(err); } finally { textarea.remove(); } } }
The copyToClipboard()
function takes the text you want to copy as a parameter
and copies the text to the user's clipboard.
The function is async, so you
have to await
it.
The function checks if the context is secure using the window.isSecureContext
property.
if (navigator.clipboard && window.isSecureContext) { await navigator.clipboard.writeText(textToCopy); }
This way you won't get the "Cannot read properties of undefined (reading
'writeText')" error even if the navigator.clipboard
property is undefined.
If the context is secure, the window.isSecureContext
property returns true
and the if
block runs.
Inside the if
block, we use the navigator.clipboard.writeText()
method to
copy the specified text to the user's clipboard.
If the context is not secure, the else
block runs.
else { const textarea = document.createElement('textarea'); textarea.value = textToCopy; // Move the textarea outside the viewport to make it invisible textarea.style.position = 'absolute'; textarea.style.left = '-99999999px'; document.body.prepend(textarea); // highlight the content of the textarea element textarea.select(); try { document.execCommand('copy'); } catch (err) { console.log(err); } finally { textarea.remove(); } }
Inside the else block, we create a textarea
element to use an old trick.
value
of the textarea
element to the text we want to copy.textarea
outside the viewport to make it invisible.select()
method to highlight the text in the textarea
element.Once the text is highlighted, we use the document.execCommand() method to copy the selected text.
try { document.execCommand('copy'); } catch (err) { console.log(err); } finally { textarea.remove(); }
Even though the document.execCommand
method is deprecated, it is still widely
supported by browsers as shown in
this table.
The copyToClipboard()
function:
navigator.clipboard
API if it is available in the environment.document.execCommand
method as a fallback if navigator.clipboard
is not available.This way the text is copied to the user's clipboard regardless if the context is secure (HTTPS).
To use the copyToClipboard
function, pass it the text you want to copy to the
user's clipboard and
await the Promise.
const button = document.getElementById('btn'); button.addEventListener('click', async () => { try { await copyToClipboard('The text you want to copy ๐'); console.log('Copied!'); } catch (err) { console.log(err); } });
Notice that we marked the callback function we passed to
addEventListener
as async
to be able to use the await
keyword.
We await the Promise that the copyToClipboard
function returns.
You can also enable clipboard access for the specific URL in the "Privacy and security" tab in Chrome:
If you don't see the site under Recent activity, click on View permissions and data stored across sites and select the specific site.
After you allow clipboard access to the site, you should be able to use the
navigator.clipboard
API.
navigator.clipboard
to be undefined
The navigator.clipboard
property might be undefined
and cause the "Cannot
read properties of undefined (reading 'writeText')" error for multiple
reasons:
navigator.clipboard
API in an insecure context (HTTP, and not
HTTPS).navigator.clipboard
API is not
supported.navigator.clipboard
API when the user hasn't focused the
tab in the browser. The browser tab has to have focus for you to be able to
use the navigator.clipboard
API.navigator.clipboard
API.navigator.clipboard.writeText()
method.You can learn more about the related topics by checking out the following tutorials: