Use the clipboard

Use navigator.clipboard to exchange text with other applications. Request only the access needed for the operation, then handle missing content and permission failures explicitly.

data-src=../_shared/prerequisites.md

Request clipboard access

By default, UXP plugins can't access the system clipboard; this protects users from unwanted data access. If your plugin needs to read or write clipboard content, you must declare the right clipboard permission in your manifest.json.

Choose the most appropriate permission level:

Permission
Access Level
Use When
"read"
Read-only
Your plugin only needs to paste or read data
"readAndWrite"
Read and write access
Your plugin needs to copy and paste data
data-variant=info
data-slots=heading, text
Pick the least-permissive option that meets your needs
In future versions, users may be asked to grant consent for clipboard access, and they'll be more comfortable approving read-only access unless your plugin clearly needs to write data.

Use the Clipboard API

The clipboard is accessed through navigator.clipboard, which provides two main methods:

Both methods work with MIME type objects, where keys represent data formats (like "text/plain") and values contain the actual content.

Write text

Call setContent() with a MIME-keyed object:

data-slots=heading, code
data-repeat=2
data-languages=JavaScript, JSON

index.js

async function copyToClipboard(text) {
  try {
    await navigator.clipboard.setContent({
      "text/plain": text
    });
    console.log("Text copied to clipboard");
  } catch (error) {
    console.error("Failed to copy to clipboard:", error);
  }
}

// Example usage
copyToClipboard("Welcome to UXP!");

manifest.json

{
  "requiredPermissions": {
    "clipboard": "readAndWrite"
  }
}

Read text

You can also read content that users have copied from other applications.

data-slots=heading, code
data-repeat=2
data-languages=JavaScript, JSON

index.js

async function pasteFromClipboard() {
  try {
    const clipboardData = await navigator.clipboard.getContent();

    if (clipboardData["text/plain"]) {
      console.log(`Pasted text: ${clipboardData["text/plain"]}`);
      return clipboardData["text/plain"];
    } else {
      console.log("No text data found on clipboard");
      return null;
    }

  } catch (error) {
    console.error("Failed to read from clipboard:", error);
  }
}

// Example usage
pasteFromClipboard();

manifest.json

{
  "requiredPermissions": {
    "clipboard": "read"
  }
}
data-variant=info
data-slots=text
This example requests "read" because it never writes to the clipboard. Use the minimum permission level required by the complete workflow.

Read, transform, and write text

Request "readAndWrite" when one operation reads existing content and writes a transformed value back:

// Transform clipboard text to uppercase
async function transformClipboardText() {
  try {
    // Read current clipboard content
    const data = await navigator.clipboard.getContent();

    if (data["text/plain"]) {
      const originalText = data["text/plain"];
      const transformedText = originalText.toUpperCase();

      // Write the transformed text back
      await navigator.clipboard.setContent({
        "text/plain": transformedText
      });

      console.log(`Transformed: "${originalText}" to "${transformedText}"`);
    } else {
      console.log("No text found on clipboard");
    }

  } catch (error) {
    console.error("Failed to transform clipboard text:", error);
  }
}

// Example usage
transformClipboardText();

For this use case, your manifest would need "readAndWrite" permission.