DOMException on calling navigator.clipboard.readText()
Asked Answered
C

15

80

Following lines of code used to work and stopped working after chrome upgrade to Version 74.0.3729.169 (Official Build) (64-bit). Now I get DOMException even though permission is set correctly. Appreciate if you can explain what is the bug and workaround. Exception details:

NotAllowedError: Document is not focused | code:0

navigator.permissions.query({ name: 'clipboard-read' }).then(result => {
// If permission to read the clipboard is granted or if the user will
// be prompted to allow it, we proceed.
    if (result.state === 'granted' || result.state === 'prompt') {
        navigator.clipboard.readText()
            .then(text => {
                //my code to handle paste
             })
             .catch(err => {
                 console.error('Failed to read clipboard contents: ', err);
             });
     }
});
Cuddy answered 25/5, 2019 at 15:21 Comment(1)
Workaround, Just paste it in setTimeout, and then focus on document.Eruct
K
68

This seems to happen when executing code from the devtools console or snippets.

Workaround:

You can execute the code below and focus on the window within 3 seconds, by clicking somewhere, or just by pressing <tab>.

e.g. from snippets

Ctrl-Enter
<Tab>

e.g. from console

Enter
<Tab>

setTimeout(async()=>console.log(
     await window.navigator.clipboard.readText()), 3000)
Kata answered 14/4, 2020 at 19:50 Comment(4)
Great answer! I posted a time-insensitive answer based on this: stackoverflow.com/a/70386674Iridosmine
Very good Workaround \o/Manolo
You are Messaih!Rajasthan
This happens also when a "lengthy" process to generate content (generating image from HTML element for instance) enables the user to focus on another tab of the browser or another application on the operating system. When the invocation of Clipboard.write takes place the error "Document not foucussed" rises. Has nothing to do with developer tools whatsoever...Restrictive
S
44

The issue I was having was that I had an alert to say that the text had been copied, and that was removing focus from the document. Ironically, this caused the text to not be copied. The workaround was quite simple:

    clipboard.writeText(clippy_button.href).then(function(x) {
      alert("Link copied to clipboard: " + clippy_button.href);
    });

Just show the alert when the Promise is resolved. This might not fix everybody's issue but if you came here based on searching for the error this might be the correct fix for your code.

Slope answered 8/4, 2022 at 22:25 Comment(5)
Yes, I get this issue too. Ironically I copy it from w3schools. Removing the alert or changing to async/await style can prevent this issue.Brit
@Brit When I search for anything javascript related on the internet I always add "mdn" to my search line so they will bubble up to the top. I've not been impressed with w3schools and avoid it.Slope
You saved my day! I had a snackbar that pops up during the copy, which removes the focus from the document. I just needed to move that after the write function. Thank!Verdure
Thanks. This not only solved my problem, but also let me know that we're using Promises in JS since... when? Anyway, TIL thanks!Kaiulani
Thanks for the hint, the alert was my problem as well!Yl
F
19

As Kaiido said, your DOM need to be focused. I had the same problem during my development when i put a breakpoint in the code... The console developper took the focused and the error appear. With the same code and same browser, all work fine if F12 is closed

Fremantle answered 11/6, 2019 at 13:31 Comment(0)
I
11

Problem

It's a security risk, clearly. :)

Solution

I assume you face this when you are trying to call it from the dev tools. Well, to make life easier, I am taking Jannis's answer, to a less adrenaline-oriented way. :)

I am adding a one-time focus listener to window to do the things magically after hitting "tab" from the Devtools.

function readClipboardFromDevTools() {
    return new Promise((resolve, reject) => {
        const _asyncCopyFn = (async () => {
            try {
                const value = await navigator.clipboard.readText();
                console.log(`${value} is read!`);
                resolve(value);
            } catch (e) {
                reject(e);
            }
            window.removeEventListener("focus", _asyncCopyFn);
        });
    
        window.addEventListener("focus", _asyncCopyFn);
        console.log("Hit <Tab> to give focus back to document (or we will face a DOMException);");
    });
}

// To call:
readClipboardFromDevTools().then((r) => console.log("Returned value: ", r));

Note: The return value is a Promise as it's an asynchronous call.

Iridosmine answered 16/12, 2021 at 23:12 Comment(2)
Fun fact: The first time you copy/paste this and hit <enter> in dev-tools, you will see these lines printed again. That means it works -- that's the content of your clipboard. ;DIridosmine
Could this be a candidate for the quine programs hall of fame :) ?Kata
C
4

if you want to debug a and play around to view result. also can hide this <p></p>.

async function readClipboard () {
  if (!navigator.clipboard) {
    // Clipboard API not available
    return
  }

  try {
    const text = await navigator.clipboard.readText();
    document.querySelector('.clipboard-content').innerText = text;
  } catch (err) {
    console.error('Failed to copy!', err)
  }
}

function updateClipboard() {
  // Here You Can Debug without DomException
  debugger
  const clipboard = document.querySelector('.clipboard-content').innerText;
  document.querySelector('.clipboard-content').innerText = 'Updated => ' + clipboard;
}
<button onclick="readClipboard()">Paste</button>
<p class="clipboard-content"></p>
<button onclick="updateClipboard()">Edit</button>
Calendar answered 28/1, 2020 at 17:36 Comment(0)
K
3

In latest Chrome dev tools, there is an option called "Emulate a focused page" in its Rendering panel. You can simply enable that option and then the clipboard code would

Kist answered 22/2, 2023 at 23:58 Comment(0)
C
2

I was facing this in a Cypress test, this fixed it for me:

  1. first focus the copy icon/button which is about to be clicked, then
  2. use cy.realClick from cypress-real-events instead of cy.click
Casebook answered 12/1, 2022 at 22:24 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Chlamydospore
S
2

You can simply add an alert which focus your document and then run what you want after it right away like so:

  alert("Copied to clipboard.");
  navigator.clipboard.writeText("a sample text!");
Stricklan answered 5/3, 2023 at 13:28 Comment(1)
still fails to copy to clipboardEx
U
1

Suppose there is a p element. you want to copy its innerText. So, lets not use navigation.clipboard (because 0f the error your are facing)

So below given is a example which copies the innerText of the p element when that button is clicked. your do not to rely upon "clicking" the button manually by using the code below. you can trigger the "click" by executing code like pElement.click() from devtools console.

Your devtools console problem, that @jannis-ioannou mentioned in his post above, will not occur!

function myFunction() {
  var copyText = document.getElementById("copy-my-contents");
  var range = document.createRange();
  var selection = window.getSelection();
  range.selectNodeContents(copyText);  
  selection.removeAllRanges();
  selection.addRange(range);
  document.execCommand("copy");
}
<p id="copy-my-contents">copy-me</p>
<button onclick="myFunction()">Copy text</button>
Upstream answered 27/7, 2021 at 14:39 Comment(1)
The html copy method is deprecated. developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/… "Working with the clipboard in extensions is transitioning from the Web API document.execCommand method (which is deprecated) to the navigator.clipboard method."Welby
C
1

I just discovered that I don't need to write any code to debug this. When you pause on a breakpoint in Chrome DevTools, it adds a small yellow box to the page you're debugging which says, "Paused in debugger" and has play and step over buttons. I've never used it before, preferring the more extensive controls in DevTools.

I just discovered that if you use the step over button in this yellow box, the DOM stays focused and no error is thrown.

Celindaceline answered 12/4, 2022 at 17:13 Comment(0)
C
1

Cypress - Use the right window/navigator and focus on the document.

I tried to programatically populate the clipboard in my Cypress test so I could paste the contents into a text-area input element. When I was struggling with this issue I found out that there were two things causing the problem.

The first issue was that I used the wrong window. Inside the test function scope window returns the Window object in test scope, while cy.window() returns the Window object for the Application Under Test (AUT). Second issue was that document was not in focus, which can be easily resolved by calling cy.window().focus();.

Since both result in the same DOMException:

NotAllowedError: Document is not focused.

It was not always clear that there were 2 issues going on. So when debugging this:

  1. Make sure you use the right window/navigator of the page you are testing.
  2. Make sure that the document is focused on.

See following Cypress tests demonstrating the above:

describe('Clipboard tests', () => {
  before(() => {
    cy.visit('/');
    // Focus on the document
    cy.window().focus();
  });

  it('window object in test scope is not the window of the AUT', () => {
    cy.window().then((win) => {
      expect(window === win).to.equal(false);
      expect(window.navigator === win.navigator).to.equal(false);
    })
  });

  it('See here the different results from the different Window objects', () => {
    expect(window.navigator.clipboard.writeText('test').catch(
      (exception) => {
        expect(exception.name).to.equal('NotAllowedError')
        expect(exception.message).to.equal('Document is not focused.')
      },
    ));

    cy.window().then((win) => {
      return win.navigator.clipboard.writeText('test').then(() => {
        return win.navigator.clipboard.readText().then(
          result => expect(result).to.equal('test'),
        );
      });
    });
  })
});
Crocker answered 17/11, 2022 at 14:56 Comment(0)
T
0

As the exception message says, you need to have the Document actively focused in order to use this API.

Trapan answered 25/5, 2019 at 15:21 Comment(2)
This is what the exception says but how to actually fix that? Is there a programmatic way?Windywindzer
@virus you could make the request while handling a click event.Trapan
S
0

We saw a handful of these in our production app, and after some digging it turned out that the root cause in our case was the user was copying a lot of data, and switched tabs during the process (thus causing the relevant DOM to lose focus, and triggering the error). We were only able to replicate this by using CPU throttling in chrome, and even then it doesn't happen every time!

There was nothing to be "fixed" in this case - instead we're just catching the error and notifying the user via a toast that the copy failed and that they should try again. Posting in case it's of use to anyone else seeing this!

Submersible answered 18/5, 2022 at 12:18 Comment(0)
S
0

If you're using Selenium and getting this, you need to bring the test window to the front:

webDriver.switchTo().window(webDriver.getWindowHandle());

I have to do this repeatedly so I have it in a loop with a Thread.sleep() until the the paste works.

Full details: https://mcmap.net/q/146370/-how-to-paste-text-from-clipboard-through-selenium-webdriver-and-java

Shend answered 23/5, 2022 at 22:34 Comment(0)
E
0

Browser requires user-interactive event or already focused to copy/read to/from clipboard. A solution is wait for a click:

async function wait(){
    await window.navigator.clipboard.writeText("foobar");
    document.removeEventListener("click",wait);
}
document.addEventListener("click",wait);
Ex answered 7/3 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.