/** Write contents of the textarea to the clipboard when clicking "Copy" */ copy.onclick = function() { navigator.clipboard.writeText(out.value) .then(() => { log('Text copied.'); }) .catch(log); }; /** Read from clipboard when clicking the Paste button */ paste.onclick = function() { navigator.clipboard.readText() .then(text => { out.value = text; log('Text pasted.'); }) .catch(() => { log('Failed to read clipboard'); }); }; /** Watch for pastes */ navigator.clipboard.addEventListener('clipboardchange', e => { navigator.clipboard.getText().then( text => { log('Updated clipboard contents: '+text) }) }); /** The 4 available permissions for Async Clipboard API: */ const PERMISSIONS = [ { name: "clipboard-read" }, { name: "clipboard-write" } //{ name: "clipboard-read", allowWithoutGesture: false }, //{ name: "clipboard-read", allowWithoutGesture: true }, //{ name: "clipboard-write", allowWithoutGesture: false }, //{ name: "clipboard-write", allowWithoutGesture: true } ]; /** Query for each permission's state, then watch for changes and update buttons accordingly: */ Promise.all( PERMISSIONS.map( descriptor => navigator.permissions.query(descriptor) ) ).then( permissions => { permissions.forEach( (status, index) => { let descriptor = PERMISSIONS[index], name = permissionName(descriptor), btn = document.createElement('button'); btn.title = 'Click to request permission'; btn.textContent = name; // Clicking a button (re-)requests that permission: btn.onclick = () => { navigator.permissions.request(descriptor) .then( status => { log(`Permission ${status.state}.`); }) .catch( err => { log(`Permission denied: ${err}`); }); }; // If the permission status changes, update the button to show it status.onchange = () => { btn.setAttribute('data-state', status.state); }; status.onchange(); permbuttons.appendChild(btn); }); }); function permissionName(permission) { let name = permission.name.split('-').pop(); if ('allowWithoutGesture' in permission) { name += ' ' + (permission.allowWithoutGesture ? '(without gesture)' : '(with gesture)'); } return name; } function log(value) { clearTimeout(log.timer); if (toast.hidden) toast.textContent = value; else toast.textContent += '\n' + value; toast.className = String(value).match(/error/i) ? 'error' : ''; toast.hidden = false; log.timer = setTimeout( () => { toast.hidden = true; }, 3000); }
<h1>Async Clipboard API Demo</h1> <section> <button id="copy"><strong>Copy</strong><br><em>(write to clipboard)</em></button> <button id="paste"><strong>Paste</strong><br><em>(read from clipboard)</em></button> </section> <textarea id="out" placeholder="Text to copy"></textarea> <h3>Permissions:</h3> <section id="permbuttons"></section> <div id="toast" hidden></div>