There are several problems.
- chrome://extensions UI is misleading you by showing old errors without indicating they're old before you changed and fixed your background script. You'll have to account for this poor design and click the "Clear all" button every time you reload the extension.
- The background script (the service worker) doesn't have `document` or `window`. This script is generally only necessary to process `chrome` events like chrome.tabs.onUpdated. In this case you don't need the background script at all, simply process DOM events in your visible page e.g. in the action popup.
- ManifestV3 extensions can't use inline code in `<script>` element. You should use a separate popup.js file and load it as <script src="popup.js"></script>
The popup runs only when shown, so you'll just read the clipboard right away. The only way to do it inside the popup is by using the deprecated document.execCommand due to
https://crbug.com/1337152.
popup.html:
<!DOCTYPE html>
<h1>Clipboard Text</h1>
<textarea id="clipboardText"></textarea>
<script src="popup.js"></script>
popup.js:
const el = document.getElementById('clipboardText');
el.focus();
el.select();
document.execCommand('paste');
If you also want to dynamically update the element while the popup is shown, you'll have to inject a content script that listens to 'copy' event, but that'll be unreliable as it won't see the text copied from the address bar or from another application, so a more reliable approach would be polling the clipboard in popup.js.
popup.html:
<!DOCTYPE html>
<h1>Clipboard Text</h1>
<textarea id="clipboardText"></textarea>
<textarea id="paste" style="opacity:0; width:1px; height:1px; border:none"></textarea>
<script src="popup.js"></script>
popup.js:
paste(true);
setInterval(paste, 250);
function paste(force) {
const elText = document.getElementById('clipboardText');
const tmp = document.getElementById('paste');
tmp.focus();
tmp.select();
document.execCommand('paste');
if (force || elText.value !== tmp.value) {
elText.value = tmp.value;
}
}