Async Clipboard API 向け SVG サポート

Async Clipboard API の Clipboard インターフェースは、システム クリップボードのコンテンツへの読み取り / 書き込みアクセスを提供します。これにより、ウェブ アプリケーションで切り取り、コピー、貼り付けの機能を実装できます。read() メソッドを呼び出すことで、クリップボードからアプリにデータを貼り付けることができます。また、write() メソッドを呼び出すことで、クリップボードにデータをコピーできます。テキスト、Portable Network Graphics(PNG)形式の画像、サニタイズされたサニタイズされていない HTMLウェブ カスタム形式に加えて、Async Clipboard API で SVG 画像のコピーと貼り付けもサポートされるようになりました。つまり、SVG を扱う画像編集ソフトウェアで、SVG 画像をテキストとしてではなく画像としてコピーして貼り付けることで、より自然に操作できるようになります。ハック的な回避策を使用する必要もなくなります。

SVG サポートの機能検出

静的 ClipboardItem.supports() メソッドを呼び出し、必要な MIME タイプを渡すことで、SVG 画像(およびその他の MIME タイプ)のサポートを検出します。

const supportsSVG = () => {
  if (
    !('supports' in window.ClipboardItem) ||
    !window.ClipboardItem.supports('image/svg+xml')
  ) {
    return false;
  }
  return true;
};

SVG 画像をコピーする

ClipboardItem にオブジェクトを入力して、SVG 画像をコピーします。SVG 画像データを含む BLOB が値で、BLOB の型(この場合は 'image/svg+xml')がキーになります。

copyButton.addEventListener('click', async () => {
  if (!supportsSVG()) {
    return;
  }
  try {
    const blob = await fetch(img.src).then((response) => response.blob());
    await navigator.clipboard.write([
      new window.ClipboardItem({
        [blob.type]: blob,
      }),
    ]);
  } catch (err) {
    console.error(err.name, err.message);
    alert(err.message);
  }
});

SVG 画像を貼り付ける

SVG 画像を貼り付けるには、クリップボードから ClipboardItem を読み取り、getType() メソッドで必要な型(この場合は 'image/svg+xml')を取得します。これは、blob URL に変換された blob を返します。この blob URL は <img>src 属性に割り当てることができます。

pasteButton.addEventListener('click', async () => {
  if (!supportsSVG()) {
    return;
  }
  const [clipboardItem] = await navigator.clipboard.read();
  const svgBlob = await clipboardItem.getType('image/svg+xml');
  if (!svgBlob) {
    alert('No SVG in the clipboard.');
    return;
  }
  const image = document.createElement('img');
  const blobURL = URL.createObjectURL(svgBlob);
  image.addEventListener('load', () => {
    URL.revokeObjectURL(blobURL);
  });
  image.src = blobURL;
});

サニタイズ

SVG は、埋め込みスクリプトなどを許可する強力な形式です。ユーザーが不明なソースからコンテンツを貼り付けると危険な可能性があるため、ブラウザはサニタイズ処理を実行します。データがコピーされると、Async Clipboard API は整形式の SVG ドキュメントを生成し、それをクリップボードに書き込みます。データが貼り付けられると、フラグメント パーサーによって厳密に処理された SVG フラグメントが生成されます。したがって、貼り付け操作の前は onclick イベント ハンドラ属性はまだ存在しますが、貼り付け時に削除されます。

macOS のクリップボード ビューア アプリでクリップボードの内容を検査している様子。これは、SVG の onclick イベント リスナー属性がまだ存在することを示しています。
macOS のクリップボード ビューア アプリがクリップボードの内容を検査している様子。SVG の onclick イベント リスナー属性がまだ存在していることがわかります。

デモ

デモで SVG のコピーと貼り付けを試してみましょう。その仕組みについては、ソースコードをご覧ください。コピー&ペーストの前後に、いずれかの円をクリックしてみてください。貼り付け後、潜在的に危険な onclick イベント ハンドラ属性が削除されます。

謝辞

Chromium の Async Clipboard API の SVG サポートは、Microsoft Edge チームによって実装されました。この記事は、Rachel Andrew と Anupam Snigdha によってレビューされました。