The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Copy plain text | await navigator.clipboard.writeText(text) | View examples |
| Read plain text | const text = await navigator.clipboard.readText() | View examples |
| Write multiple formats | await navigator.clipboard.write([new ClipboardItem({ 'text/plain': plainBlob, 'text/html': htmlBlob })]) | View examples |
| Inspect clipboard items | const items = await navigator.clipboard.read() | View examples |
| Check a write type | ClipboardItem.supports('image/png') | View examples |
| Customize a copy | event.clipboardData.setData('text/plain', value) | View examples |
| Inspect a paste | const text = event.clipboardData.getData('text/plain') | View examples |
| Replace default paste | event.preventDefault() | View examples |
| Detect API availability | if (isSecureContext && navigator.clipboard) { /* enhance */ } | View examples |
| Delegate clipboard access | Permissions-Policy: clipboard-read=(self), clipboard-write=(self) | View examples |
| Open the share chooser | await navigator.share({ title, text, url }) | View examples |
| Validate file sharing | navigator.canShare?.({ files }) | View examples |
| Register a PWA share target | "share_target": { "action": "/share/", "method": "POST", "params": { "text": "text" } } | View examples |
Clipboard and sharing features cross a privacy boundary between a page and the user's device. Offer them through clearly labeled controls, call protected APIs directly from a user action, and handle rejection without implying that data was copied or shared. Prefer plain text unless richer formats are necessary, treat pasted or received content as untrusted input, and preserve an ordinary fallback such as selectable text, a link, or a download when platform integration is unavailable.
Step by step
Detailed examples
Copy and read plain text through explicit controls
navigator.clipboard is restricted to secure contexts and protected by browser permission and activation rules. writeText and readText return promises, so success feedback belongs after fulfillment and failures need a useful alternative. Clipboard reads are more sensitive than writes and may prompt, require focused-document interaction, or be denied outright. Invoke the operation directly in the click or paste flow instead of after unrelated asynchronous work that may consume transient activation. Never poll the clipboard, and do not overwrite it on page load.
const button = document.querySelector('#copy');
const status = document.querySelector('#copy-status');
button.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText('https://example.com/report/42');
status.textContent = 'Link copied.';
} catch (error) {
status.textContent = 'Copy unavailable. Select the link and copy it manually.';
}
}); Offer rich clipboard formats with a plain-text representation
write and read exchange ClipboardItem objects keyed by MIME type. When copying rich HTML, include text/plain so destinations that do not accept HTML still receive useful content. Feature support varies by type and browser; ClipboardItem.supports can test write support, while a rejected promise remains the authoritative outcome. On read, inspect item.types, request only a type you understand with getType, constrain blob sizes, and treat HTML, SVG, images, and files as hostile input. Never inject pasted HTML with innerHTML unless a well-reviewed sanitizer and content policy are in place.
async function copyCitation() {
const plain = 'Platform APIs — https://example.com/platform';
const html = '<p><strong>Platform APIs</strong> — <a href="https://example.com/platform">source</a></p>';
const item = new ClipboardItem({
'text/plain': new Blob([plain], { type: 'text/plain' }),
'text/html': new Blob([html], { type: 'text/html' })
});
await navigator.clipboard.write([item]);
} Customize user-initiated copy, cut, and paste synchronously
copy, cut, and paste events expose an event-scoped DataTransfer through clipboardData. A handler can inspect available types, set copy or cut representations, or replace paste insertion. Call preventDefault only when your handler fully implements the expected result; a cut handler must also remove the selected content appropriately. Data access is intended inside the event handler, and a synthetic ClipboardEvent cannot read from or write to the real system clipboard. Preserve normal keyboard shortcuts and avoid silently changing copied URLs or commands, which can enable phishing or self-XSS.
const field = document.querySelector('#slug');
field.addEventListener('paste', event => {
const text = event.clipboardData.getData('text/plain');
if (!text) return;
event.preventDefault();
const normalized = text.trim().toLowerCase().replace(/[^a-z0-9-]+/g, '-');
field.setRangeText(normalized, field.selectionStart, field.selectionEnd, 'end');
field.dispatchEvent(new InputEvent('input', { bubbles: true, inputType: 'insertFromPaste', data: normalized }));
}); Design for focus, user activation, policy, and denial
Clipboard access depends on a secure context, an active and focused document, user-agent policy, user activation, and sometimes a permission grant. These details differ across engines, and Permissions API descriptors for clipboard access are not uniformly exposed; feature detection plus handling NotAllowedError is more portable than blocking the UI on a permission query. Embedded documents may additionally need clipboard-read or clipboard-write delegated by the Permissions-Policy response header and an iframe allow attribute. Keep the initiating button visible, explain what will be copied or read, and provide selectable content or a standard paste field when access is unavailable.
<label for="share-link">Share link</label>
<input id="share-link" value="https://example.com/guide" readonly>
<button id="copy-link" type="button">Copy link</button>
<p id="copy-result" aria-live="polite"></p>
<script>
const copyButton = document.querySelector('#copy-link');
const shareLink = document.querySelector('#share-link');
const copyResult = document.querySelector('#copy-result');
copyButton.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(shareLink.value);
copyResult.textContent = 'Copied.';
} catch {
shareLink.select();
copyResult.textContent = 'Press Ctrl+C or Command+C to copy the selected link.';
}
});
</script> Local code tester
Try share with a copy fallback
Use a direct user action to open the platform share chooser when supported or copy the visible URL when it is not.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



