Softex CelwareTech Blog
バニラJS Webアプリ2026-09-24

Chrome拡張のポップアップから入力欄へ確実に文字を挿入する

ポップアップのフォーカス問題、VueやReactの入力イベント、同じclassの別textareaを考慮して、Chrome拡張からページの入力欄へ文字を確実に挿入する方法を解説します。

Chrome拡張機能JavaScript入力欄VueReactcontent script

Chrome拡張のポップアップから、開いているページのtextareaへ定型文を挿入したいことがあります。しかしポップアップを開くとページ側のフォーカスが外れ、execCommand("insertText")が成功を返しても値が変わらない場合があります。

さらに、VueやReactが管理する入力欄では、DOMのvalueを書き換えるだけではフレームワーク側の状態が更新されません。同じclassのメモ欄が存在すると、別の欄へ誤挿入する危険もあります。

期待値と実値を比較する

まず元の値、選択範囲、挿入後に期待する値を作ります。execCommandを試した後に実値を比較し、一致すればそのまま使います。

function insertIntoInput(input, text) {
  const before = input.value;
  const start = input.selectionStart ?? before.length;
  const end = input.selectionEnd ?? start;
  const expected = before.slice(0, start) + text + before.slice(end);

  input.focus();
  input.setSelectionRange(start, end);
  let executed = false;
  try { executed = document.execCommand('insertText', false, text); } catch (_) {}

  if (executed && input.value === expected) return 'execCommand';
  if (input.value !== before) return 'execCommand';

  setNativeValue(input, expected);
  input.setSelectionRange(start + text.length, start + text.length);
  return 'nativeValue';
}

execCommandが別の形で値を入れていた場合は、二重挿入を避けるため、その時点で成功扱いにします。

フレームワークのsetterとイベントを使う

function setNativeValue(element, value) {
  const proto = element.tagName === 'TEXTAREA'
    ? HTMLTextAreaElement.prototype
    : HTMLInputElement.prototype;
  Object.getOwnPropertyDescriptor(proto, 'value').set.call(element, value);
  element.dispatchEvent(new Event('input', { bubbles: true }));
  element.dispatchEvent(new Event('change', { bubbles: true }));
}

ネイティブsetterで値を設定し、inputとchangeを発火します。送信ボタンを押したときにフレームワークが挿入文字を認識しているか、実際の画面で確認します。

表示中の入力欄を優先する

入力欄をclassだけで決めず、候補セレクタを順番に試します。getClientRects().length > 0で表示中の要素を優先し、メモ欄などの除外条件もセレクタへ含めます。

function findVisibleFirst(selectors) {
  let first = null;
  for (const selector of selectors) {
    for (const element of document.querySelectorAll(selector)) {
      if (element.getClientRects().length > 0) return element;
      first = first || element;
    }
  }
  return first;
}

成功後にポップアップ側でwindow.close()を呼ぶと、ページへフォーカスを戻し、そのまま続きを入力できます。

入力欄の近くにパネルを置く発展形

ポップアップを閉じる運用が合わない場合は、入力欄のそばにShadow DOMのパネルを置く方法があります。パネルのmousedownでpreventDefault()を呼ぶと、ボタンを押しても入力欄のフォーカスが外れにくく、通常のUndo履歴も維持できます。

ページ遷移や自動リサイズには、tabs.onUpdated、scroll、resize、inputを使って追従します。再注入されてもリスナーが二重にならないよう、ホスト要素や登録済みフラグを確認します。

まとめ

入力挿入は「値を代入するだけ」の処理ではありません。期待値との比較、ネイティブsetter、inputイベント、表示中要素の選択、挿入後のフォーカス復帰を一つの処理として設計すると、ページ側のフレームワークや複数欄の存在に強くなります。

この技術で業務改善しませんか?

Excel VBA・GAS・Webアプリで業務の自動化ツールを開発しています。 「こんなことできる?」というご相談だけでもお気軽にどうぞ。

無料相談はこちら →