Skip to main content
c5inco
December 19, 2021
Question

Write to Clipboard from custom plugin

  • December 19, 2021
  • 23 replies
  • 8804 views

Considering that document.execCommand is deprecated, what would the best way to write to the system clipboard within a custom plugin?

Right now, it’s a bit hacky where one can create a temporary HTML UI, set elements like textarea with the intended value to copy, then use document.execCommand. That will likely not be supported in the future, so ideally there’d be a nice and secure way to work with the system clipboard through a Figma API.

This topic has been closed for replies.

23 replies

March 20, 2023

Hey @harv_y , would you mind sharing the method that creates temporary HTML UI? I tried many different things and I was unable to copy anything to the clipboard, so at this point I’m open to any method that works, even if it’s hacky 😀

jk2K
New Participant
April 30, 2023
Alex_FG
New Participant
May 2, 2023

Here is the code I use which seems to work reliably:

function writeTextToClipboard(str) 
{
    const prevActive = document.activeElement;
    const textArea   = document.createElement('textarea');

    textArea.value = str;

    textArea.style.position = 'fixed';
    textArea.style.left     = '-999999px';
    textArea.style.top      = '-999999px';
    
    document.body.appendChild(textArea);
    
    textArea.focus();
    textArea.select();
    
    return new Promise((res, rej) => 
    {
        document.execCommand('copy') ? res() : rej();
        textArea.remove();
        
        prevActive.focus();
    });
}
function readTextFromClipboard() 
{
    let textArea = document.createElement('textarea');

    textArea.style.position = 'fixed';
    textArea.style.left     = '-999999px';
    textArea.style.top      = '-999999px';
    
    document.body.appendChild(textArea);
    
    textArea.focus();
    textArea.select();
    
    return new Promise((res, rej) => 
    {
        document.execCommand('paste') ? res(textArea.value) : rej();
        textArea.remove();
    });
}

But in cases where I’m working with a HTML input element, I don’t actually do anything myself and just let the system do its thing.

BennoDev
May 17, 2023

This is what I’m using 🙂
Its inspired by: javascript - Copy text to clipboard: Cannot read properties of undefined reading 'writeText' - Stack Overflow

import { logger } from '../../../shared';

/**
 * Unsecured fallback for copying text to clipboard
 * @param text - The text to be copied to the clipboard
 */
function unsecuredCopyToClipboard(text: string) {
  // Create a textarea element
  const textArea = document.createElement('textarea');
  textArea.value = text;
  document.body.appendChild(textArea);

  // Focus and select the textarea content
  textArea.focus();
  textArea.select();

  // Attempt to copy the text to the clipboard
  try {
    document.execCommand('copy');
  } catch (e) {
    logger.error('Unable to copy content to clipboard!', e);
  }

  // Remove the textarea element from the DOM
  document.body.removeChild(textArea);
}

/**
 * Copies the text passed as param to the system clipboard
 * Check if using HTTPS and navigator.clipboard is available
 * Then uses standard clipboard API, otherwise uses fallback
 *
 * Inspired by: https://stackoverflow.com/questions/71873824/copy-text-to-clipboard-cannot-read-properties-of-undefined-reading-writetext
 * and https://forum.figma.com/t/write-to-clipboard-from-custom-plugin/11860/12
 *
 * @param content - The content to be copied to the clipboard
 */
export function copyToClipboard(content: string) {
  // If the context is secure and clipboard API is available, use it
  if (
    window.isSecureContext &&
    typeof navigator?.clipboard?.writeText === 'function'
  ) {
    navigator.clipboard.writeText(content);
  }
  // Otherwise, use the unsecured fallback
  else {
    unsecuredCopyToClipboard(content);
  }
}
Ruslan
May 25, 2023

Hi,
Can you give a hit how to use it in code.js for noobs?

BennoDev
June 4, 2023

My shown approach only works in the ui.js part of a Figma Plugin… I could not figure out how to do it in the code.js part… Thus I send an event back to the ui.js part and copy it there to the clipboard… Since copying text to the user’s clipboard is somewhat a user “interaction” / ui task, I’m also preferring to have the clipboard logic in the ui.js part now 🙂

Example:

    uiHandler.registerEvent({
      type: 'figma.message',
      key: 'intermediate-format-export-result-event',
      callback: async (instance: TUIHandler, args) => {
        setIsLoadingIntermediateFormatExport(false);
        if (args.type === 'success') {
          setContent(args.content);
          copyToClipboard(JSON.stringify(args.content));
        }
      },
    });

Note that’ve written a uiHandler to make the interaction between code.js and ui.js more typesafe and seamless… But I hope you understand the core concept 🙂
cheers

jk2K
New Participant
August 26, 2023

me to, desktop Figma only, browser is not work

FWExtensions
December 7, 2023

The fwidgets UI library for Figma plugins makes it really easy to copy something to the clipboard. Here’s an example of copying the width and height of the selected element to the clipboard as a JS object:

// main.ts
import fwidgets from "fwidgets/main";

export default () => fwidgets(async ({ output }) => {
	const el = figma.currentPage.selection[0];
	
	if (el) {
		const { width, height } = el;
		await output.clipboard({ width, height });
	}
});

That will show the smallest possible plugin window at the bottom-right of the screen, which is necessary to perform the copy. But you don’t have to worry about setting up that UI code or dealing with messaging between the main and UI threads.

fwidgets isn’t just for copying to the clipboard, though. It also makes it easy to collect input from the user by showing UI controls with simple one-liners, for when you just want to focus on the scripting and not worry about building a whole plugin interface.

Chris_Sinco
New Member
April 1, 2025

...and now this API is broken in my plugin. What is the recommended way for plugins to copy contents to the clipboard now?

Savin_Mikhail
New Member
April 28, 2025

document.execCommand  is deprecated and doesn’t work anymore. Clipboard API always denies even reading the clipboard. Any solutions?