Skip to main content
jg-packages

Search

    Clipboard

    jg-clipboard

    Copy and read text, HTML, and images on the browser clipboard, with support detection and coded errors that say why the browser refused.

    v0.2.0BrowserESMMIT

    npm install jg-clipboard

    Usage

    Copy from a click or key press handler. Each copy calls the clipboard before its first await, so the browser still sees the gesture:

    ts
    import { copyText, ERRORS } from 'jg-clipboard';
    import { hasErrorCode } from 'jg-exception';
    
    copyButton.addEventListener('click', async () => {
      try {
        await copyText('npm install jg-clipboard');
        showToast('Copied');
      } catch (error) {
        if (hasErrorCode(error, ERRORS.CLIPBOARD_PERMISSION_DENIED)) {
          showToast('Allow clipboard access to copy');
        }
      }
    });

    Content that loads after the click can be a promise. It goes through a ClipboardItem that waits for it, which Safari needs:

    ts
    shareButton.addEventListener('click', () => {
      void copyText(fetch('/share-link').then((response) => response.text()));
    });

    Copy HTML with its plain text, and images. A PNG is copied as it is, and other types the browser can decode, such as JPEG or WebP, are redrawn as PNG, the only image type browsers accept on the clipboard:

    ts
    import { copyHtml, copyImage } from 'jg-clipboard';
    
    await copyHtml('<strong>Order #42</strong> shipped', { text: 'Order #42 shipped' });
    await copyImage(fetch('/chart.jpg').then((response) => response.blob()));

    Read from a paste button. readClipboard reads the text, HTML, and image with one call, so the person pasting sees one prompt at most. An image the browser can’t read comes back as null when text or HTML was copied with it, so the text still pastes:

    ts
    import { readClipboard, readText } from 'jg-clipboard';
    
    pasteButton.addEventListener('click', async () => {
      const { text, html, image } = await readClipboard(); // each null when the clipboard lacks it
      input.value = text ?? (await readText());
    });

    Show only what the browser supports. getClipboardSupport never throws, and reports everything as false during server rendering:

    ts
    import { getClipboardSupport } from 'jg-clipboard';
    
    const support = getClipboardSupport(); // { isSecureContext, copyText, copyHtml, copyImage, readText, read }
    copyImageButton.hidden = !support.copyImage;

    Errors

    Every failure is an Exception with one of these codes, and the browser’s error as its cause:

    Code When
    CLIPBOARD_UNSUPPORTED The page isn’t a secure context, such as HTTPS or localhost, or the browser lacks the API
    CLIPBOARD_NOT_FOCUSED The browser refused because the page doesn’t have focus
    CLIPBOARD_NO_USER_GESTURE The browser refused because the call didn’t follow a click or a key press
    CLIPBOARD_PERMISSION_DENIED The browser refused for any other reason, such as a denied or dismissed permission; data.permission holds the Permissions API’s state, or null
    CLIPBOARD_INVALID_IMAGE The image can’t be decoded as PNG: an image to copy, or one readClipboard read without text or HTML beside it
    CLIPBOARD_WRITE_FAILED A copy failed otherwise, such as content whose promise rejected
    CLIPBOARD_READ_FAILED A read failed otherwise

    Browser limits

    • The clipboard needs a secure context: HTTPS, or localhost while developing.
    • Copy and read from a click or key press handler. Safari refuses calls that don’t follow one directly, and Chromium needs the page to have focus.
    • Reading asks first. Safari and Firefox show a paste prompt each time, and Chromium asks once for the clipboard-read permission.
    • Images go on the clipboard as PNG only. Converting another type needs createImageBitmap, so it works in every current browser, but not in very old ones.
    • Without ClipboardItem, a promised text loads before the copy starts, and Safari may then refuse it.

    Generated from TSDoc

    API reference

    Every export of [email protected], 10 in all, with its signature, its errors, and an example.

    Functions

    copyHtml

    function

    Copies HTML to the clipboard, with plain text for places that can't paste HTML: options.text, or else the HTML's text content. Call it from a click or key press handler; like copyText, it calls the clipboard before its first await, and either value can be a promise.

    Signature
    copyHtml(
      html: string | Promise<string>,
      options?: ICopyHtmlOptions,
    ): Promise<void>

    Parameters

    htmlstring | Promise<string>

    The HTML, or a promise of it.

    options?ICopyHtmlOptions

    The plain text that goes with it.

    Defaults to {}.

    Returns

    Promise<void>

    A promise that resolves once the HTML is on the clipboard.

    Throws

    • CLIPBOARD_UNSUPPORTEDThe clipboard can't copy HTML here.
    • CLIPBOARD_NOT_FOCUSEDThe page must have focus to use the clipboard.
    • CLIPBOARD_NO_USER_GESTUREThe browser only allows this right after a click or a key press.
    • CLIPBOARD_PERMISSION_DENIEDThe permission to use the clipboard was denied.
    • CLIPBOARD_WRITE_FAILEDThe content couldn't be copied to the clipboard.
    Example
    import { copyHtml } from 'jg-clipboard';
    
    button.addEventListener('click', () => {
      void copyHtml('<strong>Order #42</strong> shipped', { text: 'Order #42 shipped' });
    });

    copyImage

    function

    Copies an image to the clipboard as PNG, the only image type browsers accept there. A PNG is written as it is, and other types the browser can decode, such as JPEG or WebP, are redrawn as PNG. Call it from a click or key press handler; it calls the clipboard before its first await, and the image can be a promise, such as a fetched Blob.

    Signature
    copyImage(image: Blob | Promise<Blob>): Promise<void>

    Parameters

    imageBlob | Promise<Blob>

    The image, or a promise of it.

    Returns

    Promise<void>

    A promise that resolves once the image is on the clipboard.

    Throws

    • CLIPBOARD_UNSUPPORTEDThe clipboard can't copy images here.
    • CLIPBOARD_INVALID_IMAGEThe image couldn't be decoded, so it can't be copied as PNG.
    • CLIPBOARD_NOT_FOCUSEDThe page must have focus to use the clipboard.
    • CLIPBOARD_NO_USER_GESTUREThe browser only allows this right after a click or a key press.
    • CLIPBOARD_PERMISSION_DENIEDThe permission to use the clipboard was denied.
    • CLIPBOARD_WRITE_FAILEDThe content couldn't be copied to the clipboard.
    Example
    import { copyImage } from 'jg-clipboard';
    
    button.addEventListener('click', () => {
      void copyImage(fetch('/chart.png').then((response) => response.blob()));
    });

    copyText

    function

    Copies text to the clipboard. Call it from a click or key press handler. It calls the clipboard before its first await, so the browser still sees that gesture. Text that loads after the click, such as from a request, can be a promise: it goes through a ClipboardItem that waits for it, which Safari needs. Browsers without ClipboardItem wait for the promise first, and may then refuse the copy.

    Signature
    copyText(text: string | Promise<string>): Promise<void>

    Parameters

    textstring | Promise<string>

    The text, or a promise of it.

    Returns

    Promise<void>

    A promise that resolves once the text is on the clipboard.

    Throws

    • CLIPBOARD_UNSUPPORTEDThe clipboard can't copy text here.
    • CLIPBOARD_NOT_FOCUSEDThe page must have focus to use the clipboard.
    • CLIPBOARD_NO_USER_GESTUREThe browser only allows this right after a click or a key press.
    • CLIPBOARD_PERMISSION_DENIEDThe permission to use the clipboard was denied.
    • CLIPBOARD_WRITE_FAILEDThe content couldn't be copied to the clipboard.
    Example 1
    import { copyText } from 'jg-clipboard';
    
    button.addEventListener('click', () => {
      void copyText('npm install jg-clipboard');
    });
    Example 2
    import { copyText } from 'jg-clipboard';
    
    // the text loads after the click
    button.addEventListener('click', () => {
      void copyText(fetch('/share-link').then((response) => response.text()));
    });

    getClipboardSupport

    function

    Tells what the browser lets the page do with the clipboard, from feature detection and ClipboardItem.supports where the browser has it. It never throws, and it's safe to call during server rendering, where everything is false. A supported feature can still be refused, such as without a click or a permission.

    Signature
    getClipboardSupport(): IClipboardSupport

    Returns

    IClipboardSupport

    Whether the page is a secure context, and whether each function can run.

    Example
    import { getClipboardSupport } from 'jg-clipboard';
    
    const support = getClipboardSupport();
    if (support.copyImage) {
      showCopyImageButton();
    }

    readClipboard

    function

    Reads the clipboard's text, HTML, and image with one read() call, so the person pasting sees one prompt at most. Call it from a click or key press handler, which Safari requires. An image the browser can't read never hides the text or HTML copied with it, such as the picture of spreadsheet cells that comes with their text: the image is then null.

    Signature
    readClipboard(): Promise<IClipboardContent>

    Returns

    Promise<IClipboardContent>

    A promise that resolves to each kind of content, with null for the kinds the clipboard doesn't hold or the image it can't read. The image is PNG.

    Throws

    • CLIPBOARD_UNSUPPORTEDThe clipboard can't read here.
    • CLIPBOARD_NOT_FOCUSEDThe page must have focus to use the clipboard.
    • CLIPBOARD_NO_USER_GESTUREThe browser only allows this right after a click or a key press.
    • CLIPBOARD_PERMISSION_DENIEDThe permission to use the clipboard was denied.
    • CLIPBOARD_INVALID_IMAGEThe clipboard holds only an image, which couldn't be decoded as PNG.
    • CLIPBOARD_READ_FAILEDThe clipboard couldn't be read, or holds only an image it couldn't read.
    Example
    import { readClipboard } from 'jg-clipboard';
    
    pasteButton.addEventListener('click', async () => {
      const { html, text, image } = await readClipboard();
      if (image) {
        preview.src = URL.createObjectURL(image);
      }
    });

    readText

    function

    Reads the text on the clipboard. Browsers ask before a page reads it: Safari and Firefox show a paste prompt, and Chromium asks for the clipboard-read permission once. Call it from a click or key press handler, which Safari requires.

    Signature
    readText(): Promise<string>

    Returns

    Promise<string>

    A promise that resolves to the text, or '' when the clipboard holds none.

    Throws

    • CLIPBOARD_UNSUPPORTEDThe clipboard can't read text here.
    • CLIPBOARD_NOT_FOCUSEDThe page must have focus to use the clipboard.
    • CLIPBOARD_NO_USER_GESTUREThe browser only allows this right after a click or a key press.
    • CLIPBOARD_PERMISSION_DENIEDThe permission to use the clipboard was denied.
    • CLIPBOARD_READ_FAILEDThe clipboard couldn't be read.
    Example
    import { readText } from 'jg-clipboard';
    
    pasteButton.addEventListener('click', async () => {
      input.value = await readText();
    });

    Constants

    ERRORS

    const

    the codes for every error the package throws

    Declaration
    const ERRORS: { CLIPBOARD_UNSUPPORTED: "CLIPBOARD_UNSUPPORTED"; CLIPBOARD_PERMISSION_DENIED: "CLIPBOARD_PERMISSION_DENIED"; CLIPBOARD_NO_USER_GESTURE: "CLIPBOARD_NO_USER_GESTURE"; CLIPBOARD_NOT_FOCUSED: "CLIPBOARD_NOT_FOCUSED"; CLIPBOARD_INVALID_IMAGE: "CLIPBOARD_INVALID_IMAGE"; CLIPBOARD_WRITE_FAILED: "CLIPBOARD_WRITE_FAILED"; CLIPBOARD_READ_FAILED: "CLIPBOARD_READ_FAILED" }

    Types

    IClipboardContent

    type

    what readClipboard found, with null for each kind of content the clipboard doesn't hold

    Declaration
    type IClipboardContent = {
        text: string | null;
        html: string | null;
        image: Blob | null;
    };

    Members

    • textproperty
      string | null
    • htmlproperty
      string | null
    • imageproperty
      Blob | null

      the image, as PNG

    IClipboardSupport

    type

    what the browser lets the page do with the clipboard, each from feature detection

    Declaration
    type IClipboardSupport = {
        isSecureContext: boolean;
        copyText: boolean;
        copyHtml: boolean;
        copyImage: boolean;
        readText: boolean;
        read: boolean;
    };

    Members

    • isSecureContextproperty
      boolean

      whether the page is in a secure context, such as HTTPS or localhost, which the clipboard needs

    • copyTextproperty
      boolean

      whether copyText can run

    • copyHtmlproperty
      boolean

      whether copyHtml can run

    • copyImageproperty
      boolean

      whether copyImage can run

    • readTextproperty
      boolean

      whether readText can run

    • readproperty
      boolean

      whether readClipboard can run

    ICopyHtmlOptions

    type

    what copyHtml accepts besides the HTML

    Declaration
    type ICopyHtmlOptions = {
        text?: string | Promise<string>;
    };

    Members

    • textproperty
      string | Promise<string>

      the plain text pasted where HTML can't go. Defaults to the HTML's text content