k8o

任意のデータをコピー&ペーストするClipboard API

公開: 2025年4月6日(日)
更新: 2025年4月6日(日)
閲覧数123 views

Clipboard APIは、navigator.clipboardを通じてクリップボードへの読み書きを非同期で行えるAPIです。テキストや画像のコピー・貼り付けに対応し、ClipboardItemを使えばMIMEタイプ別のデータ操作も可能です。

JavaScriptBaseline 2025Baseline 2024Clipboard APIClipboardItemClipboardItem supports

Clipboard API

Clipboard APIは、クリップボードにアクセスするためのAPIです。これを使うことで、ユーザーが選択したテキストや画像などをクリップボードにコピーしたり、クリップボードからデータを取得したりすることができます。

Clipboard APIはClipboardインターフェースにより実装されており、navigator.clipboardを通じてアクセスできます。

Clipboardインターフェースは、以下の非同期なメソッドを提供しています。

  • readText(): クリップボードからテキストデータを読みとる
  • writeText(): クリップボードにテキストデータを書き込む
  • read(): クリップボードからデータを読みとる
  • write(): クリップボードにデータを書き込む
// readText
navigator.clipboard.readText().then(console.log);

// writeText
navigator.clipboard
  .writeText('Hello, world!')
  .then(() => console.log('Text copied to clipboard!'));

// read
navigator.clipboard.read().then((clipboardItems) => {
  for (const clipboardItem of clipboardItems) {
    for (const type of clipboardItem.types) {
      const blob = clipboardItem.getType(type);
      console.log(blob);
    }
  }
});

// write
const item = new ClipboardItem({
  'image/png': new Blob(['...'], { type: 'image/png' }),
});
navigator.clipboard
  .write([item])
  .then(() => console.log('Image copied to clipboard!'));

readTextwriteTextは、テキストデータを扱うための簡単なメソッドです。readwriteもベースは同じですが、テキスト以外のコンテンツも扱うため少し複雑です。こちらについては後ほど詳しく紹介します。

権限

Clipboard APIはセキュリティ上の都合で実行に対する制限がかけられています。

制限はブラウザによって異なります。例えばChromeではPermissions APIを使って、clipboard-readで読み込みを、clipboard-writeで書き込みの権限を確認することができます。

const readPermission = await navigator.permissions.query({
  name: 'clipboard-read',
});

readPermission.state === 'granted'; // クリップボードの読み取りが許可されている
readPermission.state === 'prompt'; // ユーザーに許可を求める
readPermission.state === 'denied'; // クリップボードの読み取りが拒否されている

const writePermission = await navigator.permissions.query({
  name: 'clipboard-write',
});

writePermission.state === 'granted'; // クリップボードの書き込みが許可されている
writePermission.state === 'prompt'; // ユーザーに許可を求める
writePermission.state === 'denied'; // クリップボードの書き込みが拒否されている

これに対し、FirefoxやSafariでは、これらの権限はサポートされていません。FirefoxやSafariはオリジン間の読み込みは許可されていますが、異なるオリジンで読み込むことは許可されていません(書き込みはデフォルトで許可されています)。

Safariで発生するエラー: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

権限チェックとテキストの読み書き

Permission APIと合わせて、readTextwriteTextを用いた例を下に示します。

権限チェックとテキストの読み書き

クリップボードの読み取り: 読み込めませんでした

クリップボードの書き込み: 読み込めませんでした

Permission APIを使って権限判定を行なっています。SafariやFirefoxを利用の方は利用できないです🙏。

ClipboardItem

ClipboardItemは、クリップボードに書き込むデータを表すオブジェクトです。先ほどの例のreadwriteで使われているものです。 readはクリップボードから読み取ったデータをClipboardItemの配列で解決し、writeは引数に渡したClipboardItemの配列をクリップボードに書き込みます。

// read
navigator.clipboard.read().then((clipboardItems: ClipboardItem) => {
  for (const clipboardItem of clipboardItems) {
    for (const type of clipboardItem.types) {
      const blob = clipboardItem.getType(type);
      console.log(blob);
    }
  }
});

// write
const item = new ClipboardItem({
  'image/png': new Blob(['...'], { type: 'image/png' }),
});
navigator.clipboard
  .write([item])
  .then(() => console.log('Image copied to clipboard!'));

ClipboardItemは2つの引数によって組み立てられます。

1つ目の引数はオブジェクトをデータで渡します。MIMEタイプをキーに、Blobや文字列、これらをPromiseでラップしたものを値に持つオブジェクトを渡します。

{
  'image/png': new Blob(['...'], { type: 'image/png' }),
  'text/plain': 'Hello, world!',
}

2つ目の引数はオブジェクトでオプションを渡します。現在はpresentationStyleをサポートしています。値にはunspecifiedinlineattachmentを渡せます。デフォルト値は unspecifiedです。 inlineはクリップボードにコピーしたデータを表示するためのもの、attachmentはクリップボードにコピーしたデータを添付ファイルとして扱うためのものです。

作成されたClipboardItemインスタンスは、typesプロパティ、getType()メソッドを持ちます(Baselineで対応しているものだけを紹介しています)。 typesは利用可能なMIMEタイプを配列で返し、getType()は第一引数に渡したMIMEタイプをもとにPromiseで解決したBlobを返します。

const item = new ClipboardItem(
  {
    'image/png': new Blob(['...'], { type: 'image/png' }),
    'text/plain': 'Hello, world!',
  },
  { presentationStyle: 'inline' },
);
console.log(item.types); // ['image/png', 'text/plain']
for (const type of item.types) {
  item.getType(type).then((blob) => {
    // Blob {size: 3, type: 'image/png'}
    // Blob {size: 13, type: 'text/plain'}
    console.log(blob);
  });
}
item.getType('text/html').catch((err) => {
  // NotFoundError: Failed to execute 'getType' on 'ClipboardItem': The type was not found
  console.error(err);
});

ClipboardItem supports

ClipboardItemの静的メソッドsupportsがBaseline 2025で追加されました。supportsはユーザーの環境で特定のMIMEタイプがClipboard APIでサポートされていることを確認するためのものです。

text/plaintext/htmlimage/pngは常にサポートされていますが、text/uri-listimage/svg+xmlweb で始めるカスタムMIMEタイプは、ブラウザやOSによって結果が異なります。

Clipboard API and events

w3c.github.io

サポートされていればtrue、サポートされていなければfalseを返します。

ClipboardItem.supports('text/plain'); // true
ClipboardItem.supports('text/html'); // true
ClipboardItem.supports('image/png'); // true

ClipboardItem.supports('text/uri-list'); // true or false
ClipboardItem.supports('image/svg+xml'); // true or false
ClipboardItem.supports('web image/png'); // true or false

ClipboardItem.supports('application/json'); // false

PNG画像のコピーと貼り付け

ClipboardItemを利用してPNG画像のコピーと貼り付けを行う例を作成しました。

PNG画像のコピーと貼り付けを行う

コピーする画像1

ペーストされた画像

権限があれば、外部でコピーした画像も貼り付けられます

ペーストされた画像

コピーを行う関数と貼り付けを行う関数は以下のようになっています。

const copyImage = async () => {
  const img = document.getElementById(xxx) as HTMLImageElement | null;
  if (!img) return;
  const canvas = document.createElement('canvas');
  canvas.width = img.naturalWidth;
  canvas.height = img.naturalHeight;
  const ctx = canvas.getContext('2d');
  if (!ctx) return;
  ctx.drawImage(img, 0, 0);
  const blob = await new Promise<Blob>((resolve) => {
    canvas.toBlob((blob) => {
      if (!blob) {
        throw new Error('Blobが取得できませんでした');
      }
      resolve(blob);
    });
  });
  const file = new File([blob], 'xxx.png', { type: 'image/png' });
  const data = [new ClipboardItem({ 'image/png': file })];
  await navigator.clipboard.write(data);
};

const pasteImage = async () => {
  const img = document.getElementById(xxx) as HTMLImageElement | null;
  if (!img) return;
  const items = await navigator.clipboard.read();
  for (const item of items) {
    for (const type of item.types) {
      if (type === 'image/png') {
        const blob = await item.getType(type);
        const url = URL.createObjectURL(blob);
        img.src = url;
      }
    }
  }
};

おわりに

Clipboard APIは、クリップボードにアクセスするためのAPIです。これを使うことで、ユーザーが選択したテキストや画像などをクリップボードにコピーしたり、クリップボードからデータを取得したりすることができます。 過去にはexecCommand()を利用していましたが、Clipboard APIを利用することで、より簡単にクリップボードにアクセスできるようになりました。execCommand()は非推奨なので、今後はClipboard APIを利用するようにしましょう。

この記事はどうでしたか?

500文字以内でご記入ください