152

Is there a way you can copy to clipboard in Node.js? Any modules or ideas what so ever? I'm using Node.js on a desktop application. Hopefully that clears up why I want it to be able to achieve this.

Sindre Sorhus
  • 62,972
  • 39
  • 168
  • 232
Tower
  • 98,741
  • 129
  • 357
  • 507

11 Answers11

161

For OS X:

function pbcopy(data) {
    var proc = require('child_process').spawn('pbcopy'); 
    proc.stdin.write(data); proc.stdin.end();
}

write() can take a buffer or a string. The default encoding for a string will be utf-8.

Pier
  • 10,298
  • 17
  • 67
  • 113
Benjamin Atkin
  • 14,071
  • 7
  • 61
  • 60
124

Check out clipboardy. It lets you copy/paste cross-platform. It is more actively maintained than the copy-paste module mentioned in another answer and it fixes many of that module's issues.

const clipboardy = require('clipboardy');

// Copy
clipboardy.writeSync('');

// Paste
clipboardy.readSync();
//
Ecstabis
  • 434
  • 3
  • 16
Sindre Sorhus
  • 62,972
  • 39
  • 168
  • 232
  • 1
    It is better than "copy-paste" module as it supports double byte characters too. But this has issue with windows 32 bit OS. – Ponmudi VN Jul 19 '17 at 07:53
  • 3
    @PonmudiVN Windows 32-bit support has been fixed: https://github.com/sindresorhus/clipboardy/commit/3be3ee6b9b9cd736623fcc8ebb1aa9e0c42371b4 – Sindre Sorhus Dec 06 '17 at 00:21
  • I did npm install `çlipboardy` in cypress.I have a button in my web application, on click on that button should get the clipboard content but it gives undefined, any inputs are much appreciated https://stackoverflow.com/questions/61650737/how-to-fetch-copied-to-clipboard-content-in-cypress – soccerway May 07 '20 at 06:36
  • @Miquel The package is fully maintained. Your problem is actually that *your* project is not a proper ES module project. – Sindre Sorhus Jul 21 '23 at 22:27
  • @SindreSorhus I've removed commentary, last day I saw old commints (last one 2022, which is older than `copy-paste` last one). Anyway this library is not fully compatible with all project configurations, I'm working on a node.js typescript project with all libraries working but not this one. I've found that Xavi's `npm i copy-paste` works fine at first install with no problems of incompatibility. Would be awesome if this library could work with no problems with any project, regardless if it's well or not well configured (at library developer eyes) – Miquel Jul 23 '23 at 18:01
38

Here's a module that provide copy and paste functions: https://github.com/xavi-/node-copy-paste

When require("copy-paste").global() is executed, two global functions are added:

> copy("hello") // Asynchronously adds "hello" to clipbroad
> Copy complete
> paste() // Synchronously returns clipboard contents
'hello'

Like many of the other answer mentioned, to copy and paste in node you need to call out to an external program. In the case of node-copy-paste, it calls out to pbcopy/pbpaste (for OSX), xclip (for linux), and clip (for windows).

This module was very helpful when I was doing a lot of work in the REPL for a side project. Needless to say, copy-paste is only a command line utility -- it is not meant for server work.

Xavi
  • 20,111
  • 14
  • 72
  • 63
36

Shortest way in Windows:

const util = require('util');
require('child_process').spawn('clip').stdin.end(util.inspect('content_for_the_clipboard'));
toss
  • 3
  • 1
  • 4
Ernst Robert
  • 2,037
  • 4
  • 25
  • 50
  • 1
    works! thank you... But need to require `util` first. – LIXer Mar 24 '17 at 02:05
  • 9
    Thanks! no need for "util" dependency works for me like that: require('child_process').spawn('clip').stdin.end("content_for_the_clipboard"); – darmis Dec 27 '17 at 14:21
  • I got `ReferenceError: util is not defined` without first including `const util = require("util")` I tested in both Electon main and render process with no luck. That being said from node 12.14.1 CLI it worked. I think it's safe to say you should define util to be on the safe side based on use case. – Benargee Mar 14 '20 at 20:04
  • 5
    This almost works: it copies the string with single quotes around it. Does anyone know how to prevent this behavior? – m4cbeth Oct 15 '20 at 22:08
  • 5
    @m4cbeth, leave off the "util.inspect" and no single ticks. require('child_process').spawn('clip').stdin.end('content_for_the_clipboard'); – Eric Bynum May 17 '21 at 21:07
25

A clipboard is not inherent to an operating system. It's a construct of whatever window system the operating system happens to be running. So if you wanted this to work on X for example, you would need bindings to Xlib and/or XCB. Xlib bindings for node actually exist: https://github.com/mixu/nwm. Although I'm not sure whether it gives you access to the X clipboard, you might end up writing your own. You'll need separate bindings for windows.

edit: If you want to do something hacky, you could also use xclip:

var exec = require('child_process').exec;

var getClipboard = function(func) {
  exec('/usr/bin/xclip -o -selection clipboard', function(err, stdout, stderr) {
    if (err || stderr) return func(err || new Error(stderr));
    func(null, stdout);
  });
};

getClipboard(function(err, text) {
  if (err) throw err;
  console.log(text);
});
chjj
  • 14,322
  • 3
  • 32
  • 24
4

Mac has a native command line pbcopy for this usecase:

require('child_process').exec(
    'echo "test foo bar" | pbcopy',

    function(err, stdout, stderr) {
        console.log(stdout); // to confirm the application has been run
    }
);

Same code for Linux but replace pbcopy with Xclip (apt get install xclip)

FGRibreau
  • 7,021
  • 2
  • 39
  • 48
  • Interesting! Do you think there's a Windows way to do this also? And what about bundling xclip in my program as I wouldn't want to ask the user to install xclip. – Tower Oct 16 '11 at 11:45
  • 1
    I found there's something in Windows: `echo fooo | clip`. Now, how to have this in Linux without asking the user to install something? – Tower Oct 16 '11 at 11:52
  • 1
    `echo fooo | clip` can work, but the result will contains a ‘\n' at the last of the primal string, it's out of my expect. – LIXer Mar 24 '17 at 02:11
  • This wouldn't work if the string has non-english characters such as '福星高照'. – Aero Wang Aug 15 '21 at 07:12
3

I saw there wasn't a solution here or anywhere obvious that worked for Windows, so reposting this one found in the depths of page 2 on Google search, which uses the Windows native command line clip, and avoids any potentially messy usage of command line workarounds such as echo foo | clip like suggested above.

  var cp = require("child_process");
  var child = cp.spawn('clip');
  child.stdin.write(result.join("\n"));
  child.stdin.end();

Hope this helps someone!

Ben S.
  • 111
  • 1
  • 8
3

I managed to do so by creating a different application which handles this. It's certainly not the best way, but it works.

I'm on Windows and created a VB.NET application:

Module Module1

    Sub Main()
        Dim text = My.Application.CommandLineArgs(0)
        My.Computer.Clipboard.SetText(text)
        Console.Write(text) ' will appear on stdout
    End Sub
End Module

Then in Node.js, I used child_process.exec to run the VB.NET application, with the data to be copied passed as a command line argument:

require('child_process').exec(
    "CopyToClipboard.exe \"test foo bar\"",

    function(err, stdout, stderr) {
        console.log(stdout); // to confirm the application has been run
    }
);
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • Do you think you could do this within command line directly? Writing an app for this means I need to compile it for Mac, Linux and Windows. – Tower Oct 15 '11 at 17:15
  • @rFactor: I've no experience with Mac/Linux at all I'm afraid, and I'm not aware of a built-in clipboard command. – pimvdb Oct 15 '11 at 17:22
  • I use the command 'echo "test foo bar" | clip', it works. but the result has a line break \n, it breaks my work... – LIXer Aug 23 '16 at 09:25
1

If you'd like to copy a file (not its contents) to the clipboard, consider the following:

For macOS:

let filePath; // absolute path of the file you'd like to copy

require('child_process').exec(  
  `osascript -e 'set the clipboard to POSIX file "${filePath}"'`,

  function (err, stdout, stderr) {
    console.log(stdout); // to confirm the application has been run
  }
);

For Windows:

const filePath; // absolute path of the file you'd like to copy

// Make a temporary folder
const tmpFolder = path.join(__dirname, `tmp-${Date.now()}`);
fs.mkdirSync(tmpFolder, { recursive: true });

// Copy the file into the temporary folder
const tmpFilePath = path.join(tmpFolder, path.basename(filePath));
fs.copyFileSync(filePath, tmpFilePath);

// To copy the contents of the folder in PowerShell,
// you need to add a wildcard to the end of the path
const powershellFolder = path.join(tmpFolder, '*');

require('child_process').exec(
  `Set-Clipboard -PATH "${powershellFolder}"`, { 'shell': 'powershell.exe' },

  function (err, stdout, stderr) {
    console.log(stdout); // to confirm the application has been run
  }
);
JEntler
  • 11
  • 4
0

This is how you would do this on node-ffi for windows, this interacts directly with the native clipboard API from windows. (Which means you can also read/write different clipboard formats)

var {
  winapi,
  user32,
  kernel32,
  constants
} = require('@kreijstal/winffiapi')
const GMEM_MOVEABLE=0x2;
var stringbuffer=Buffer.from("hello world"+'\0');//You need a null terminating string because C api.
var hmem=kernel32.GlobalAlloc(GMEM_MOVEABLE,stringbuffer.length);
var lptstr = kernel32.GlobalLock(hmem);
stringbuffer.copy(winapi.ref.reinterpret(lptstr, stringbuffer.length));
kernel32.GlobalUnlock(hmem);
if (!user32.OpenClipboard(0)){
    kernel32.GlobalLock(hmem);
    kernel32.GlobalFree(hmem);
    kernel32.GlobalUnlock(hmem);
    throw new Error("couldn't open clipboard");
}
user32.EmptyClipboard();
user32.SetClipboardData(constants.clipboardFormats.CF_TEXT, hmem);
user32.CloseClipboard();
Rainb
  • 1,965
  • 11
  • 32
-5

check this zeroclipboard

npm install zeroclipboard

Damodaran
  • 10,882
  • 10
  • 60
  • 81