@absoluteui/services/clipboard
Copy and read text, rich content, and images, with status for announcements.
import { ... } from '@absoluteui/services/clipboard';How to use
Section titled “How to use”Copies and reads text, rich content, and images, with a fallback for older or insecure contexts that keeps focus and selection where they were. Every function resolves to a status object instead of throwing, and describeCopyStatus turns it into text for a live region. Clipboard contents are never logged. The Files and downloads guide shows the basic copy; the recipes below cover the rest.
How do I build a “Copy” button that announces the result?
Section titled “How do I build a “Copy” button that announces the result?”Copy from the click handler (browsers require a user gesture) and put the description in a polite live region. Pass labels to translate and shortcut to fix the key hint.
import { copyText, describeCopyStatus } from '@absoluteui/services/clipboard';
const region = document.createElement('div');region.setAttribute('aria-live', 'polite');const button = document.createElement('button');button.textContent = 'Copy employee ID';button.addEventListener('click', async () => { region.textContent = describeCopyStatus(await copyText('EMP-000042'));});import { describeCopyStatus } from '@absoluteui/services/clipboard';
describeCopyStatus({ ok: true, method: 'clipboard-api' }, { labels: { copied: 'In die Zwischenablage kopiert' } }); // => 'In die Zwischenablage kopiert'describeCopyStatus({ ok: false, method: 'clipboard-api', reason: 'denied' }, { shortcut: 'Ctrl+C' }); // => 'Clipboard access is blocked. Select the text and press Ctrl+C.'How do I copy a table so it pastes into a spreadsheet?
Section titled “How do I copy a table so it pastes into a spreadsheet?”copyRich puts several formats on the clipboard at once: spreadsheets and editors take the HTML, plain-text fields take the tab-separated text. Sanitize any HTML that contains user data first, for example with sanitizeHtml from @absoluteui/core.
import { escapeHtml } from '@absoluteui/helpers/string';import { copyRich } from '@absoluteui/services/clipboard';
const rows = [['Name', 'Department'], ['Ada Lovelace', 'Finance'], ['Grace Hopper', 'Engineering']];const html = `<table>${rows.map((r) => `<tr>${r.map((c) => `<td>${escapeHtml(c)}</td>`).join('')}</tr>`).join('')}</table>`;const status = await copyRich({ 'text/plain': rows.map((r) => r.join('\t')).join('\n'), 'text/html': html });How do I paste from the clipboard into a field?
Section titled “How do I paste from the clipboard into a field?”readText checks the permission first, so a user who blocked access is not prompted again. Handle denied, empty, and unsupported with a hint to paste with the keyboard.
import { readText } from '@absoluteui/services/clipboard';
const input = document.createElement('input');const hint = document.createElement('p');const pasteButton = document.createElement('button');pasteButton.addEventListener('click', async () => { const r = await readText(); if (r.ok) input.value = r.text.trim(); else hint.textContent = r.reason === 'denied' ? 'Paste is blocked. Press Ctrl+V in the field instead.' : 'Nothing to paste.';});copyBlob(pngBlob) copies an image such as a chart; it has no fallback, and most browsers accept only PNG.
What goes wrong?
Section titled “What goes wrong?”- The async clipboard needs a secure context and a user gesture. Outside a secure context, text copies use the fallback (
method: 'exec-command'); images and reads returnreason: 'unsupported'. - Nothing to copy is reported, not thrown:
import { copyRich } from '@absoluteui/services/clipboard';
await copyRich({}); // => { ok: false, method: 'none', reason: 'empty' }API reference
Section titled “API reference”Functions
Section titled “Functions”copyBlob
Copies a binary item such as an image/png Blob. There is no fallback; browsers generally
accept only image/png, text/plain and text/html.
function copyBlob(blob: Blob): Promise<CopyStatus>;Example:
const chart = document.createElement('canvas');const png = await new Promise<Blob | null>((resolve) => chart.toBlob(resolve, 'image/png'));if (png) await copyBlob(png);copyRich
Copies rich content (for example HTML with a plain-text alternative) via ClipboardItem,
falling back to a copy event that sets each type. HTML must already be sanitized.
function copyRich(data: RichClipboardData): Promise<CopyStatus>;Example:
await copyRich({ 'text/plain': 'Total: 42', 'text/html': '<b>Total:</b> 42' }); // sanitize any user-supplied HTML firstcopyText
Copies plain text. Uses the async Clipboard API in secure contexts, else (or when it is
denied) an isolated execCommand('copy') fallback that keeps focus and selection. Call it from
a user gesture.
function copyText(text: string): Promise<CopyStatus>;Example:
const status = await copyText('https://hr.example.com/invite/7Gk2');const liveRegion = document.createElement('div');liveRegion.setAttribute('aria-live', 'polite');liveRegion.textContent = describeCopyStatus(status);describeCopyStatus
Text for a live region describing a copy status.
function describeCopyStatus(value: CopyStatus, options?: DescribeCopyStatusOptions): string;Example:
describeCopyStatus({ ok: true, method: 'clipboard-api' }); // => 'Copied to clipboard'describeCopyStatus({ ok: false, method: 'none', reason: 'unsupported' }, { shortcut: 'Ctrl+C' }); // => 'Copy failed. Select the text and press Ctrl+C.'describeCopyStatus({ ok: false, method: 'none', reason: 'unsupported' }); // e.g. '… press Command+C.' on Apple platformsreadItems
Reads all clipboard items (text, HTML, images). Use item.types and item.getType(type).
function readItems(): Promise<ReadItemsResult>;Example:
const r = await readItems();const img = document.createElement('img');if (r.ok) for (const item of r.items) if (item.types.includes('image/png')) img.src = URL.createObjectURL(await item.getType('image/png'));readText
Reads plain text. Checks the permission first so a denied permission does not prompt again.
function readText(): Promise<ReadTextResult>;Example:
const r = await readText();const input = document.createElement('input');if (r.ok) input.value = r.text;else console.info(r.reason === 'denied' ? 'Paste permission is blocked.' : 'Nothing to paste.');Constants
Section titled “Constants”DEFAULT_COPY_LABELS
const DEFAULT_COPY_LABELS: CopyStatusLabels;Interfaces
Section titled “Interfaces”CopyStatus
Result of a copy.
interface CopyStatus { readonly ok: boolean; readonly method: ClipboardMethod; readonly reason?: ClipboardFailureReason;}CopyStatusLabels
Live-region messages; override for localization.
interface CopyStatusLabels { readonly copied: string; readonly failed: string; readonly denied: string; readonly empty: string;}DescribeCopyStatusOptions
interface DescribeCopyStatusOptions { readonly labels?: Partial<CopyStatusLabels>; readonly shortcut?: string;}RichClipboardData
Rich clipboard payload keyed by MIME type.
interface RichClipboardData { readonly 'text/plain'?: string; readonly 'text/html'?: string;}ClipboardFailureReason
Why an operation failed.
type ClipboardFailureReason = 'denied' | 'unsupported' | 'empty' | 'error';ClipboardMethod
How the operation was performed.
type ClipboardMethod = 'clipboard-api' | 'exec-command' | 'none';ReadItemsResult
Result of readItems.
type ReadItemsResult = { readonly ok: true; readonly items: readonly ClipboardItem[];} | { readonly ok: false; readonly reason: ClipboardFailureReason;};ReadTextResult
Result of readText.
type ReadTextResult = { readonly ok: true; readonly text: string;} | { readonly ok: false; readonly reason: ClipboardFailureReason;};