【JavaScript】指定した範囲の文字列を選択する方法|setSelectionRange・Selection API・ハイライト表示まで解説

JavaScriptで「ページ上のテキストの一部を選択状態にしたい(青く反転させたい・ハイライトしたい)」という場面があります。入力欄の一部を選択してコピーさせたり、検索ヒット箇所を強調表示したりするケースです。

選択する対象が <input> / <textarea> なのか、<p><div> などの通常要素なのかで使うAPIが変わります。この記事では setSelectionRange()・Selection API+Range・ハイライト表示・選択テキストの取得まで、ブラウザ対応とあわせて解説します。

「選択」と「抽出」は別物です。画面上で反転させる(選択)のではなく、部分文字列を値として取り出したいだけなら開始位置と文字数を指定して取得する方法(slice / substring)を参照してください。この記事は「画面上で選択・ハイライトする」処理を扱います。
使い分けの結論:入力欄(input / textarea)は el.setSelectionRange(start, end)、通常要素(p / div など)は Selection API + Range、「反転させず色だけ付けたい」なら <mark> でラップするか CSS Custom Highlight API を使います。
スポンサーリンク

input / textarea の範囲を選択する(setSelectionRange)

フォーム部品では標準メソッド setSelectionRange(開始, 終了) が使えます。選択を画面に見せるには先に focus() しておきます。

setSelectionRange() で範囲選択
const input = document.getElementById("myInput");
// 値が "Hello World" のとき

input.focus();              // 選択を表示するためフォーカスする
input.setSelectionRange(6, 11); // 6〜10文字目("World")を選択

// 全選択は select() が簡単
input.select();

選択されている範囲・文字列を取得する

入力欄では selectionStart / selectionEnd で現在の選択範囲が分かります。

選択範囲と選択文字列の取得
const input = document.getElementById("myInput");

const start = input.selectionStart; // 選択開始位置
const end = input.selectionEnd;     // 選択終了位置
const selected = input.value.substring(start, end);

console.log(selected); // 選択中の文字列

通常要素(p / div など)の範囲を選択する(Selection API)

フォーム以外の要素では setSelectionRange() は使えません。document.createRange() で範囲を作り、Selection オブジェクトに追加します。

Selection API + Range(堅牢版)
function selectRange(element, start, end) {
  const node = element.firstChild;
  // 最初の子がテキストノードでなければ中断
  if (!node || node.nodeType !== Node.TEXT_NODE) return false;

  const len = node.textContent.length;
  // 範囲を文字列の長さ内に丸める(範囲外エラー防止)
  const s = Math.max(0, Math.min(start, len));
  const e = Math.max(s, Math.min(end, len));

  const range = document.createRange();
  range.setStart(node, s);
  range.setEnd(node, e);

  const selection = window.getSelection();
  selection.removeAllRanges(); // 既存の選択を解除
  selection.addRange(range);
  return true;
}

// <p id="target">Hello World</p> の 6〜10文字目を選択
const el = document.getElementById("target");
selectRange(el, 6, 11); // "World" が選択される
テキストノードに注意:上記は要素の中身が「単一のテキスト」であることを前提にしています。<p>Hello <b>World</b></p> のように子要素を含む場合、firstChild はテキストノードでなかったり範囲が複数ノードにまたがったりするため、Range の開始・終了ノードをそれぞれ適切に指定する必要があります。

現在選択されているテキストを取得する

ユーザーがマウスで選択した範囲の文字列は window.getSelection() で取得できます。

選択中テキストの取得
// ページ全体で現在選択されているテキスト
const text = window.getSelection().toString();
console.log(text);

// 選択が変わるたびに取得する
document.addEventListener("selectionchange", () => {
  const selected = window.getSelection().toString();
  if (selected) console.log("選択中:", selected);
});

選択せずにハイライト(色付け)する

「青い選択状態」ではなく、検索ヒット箇所などを恒常的に色付けしたい場合は、該当部分を <mark> で包む方法が定番です。match()replace() で位置を探しますが、XSS対策として innerHTML ではなく textContent で組み立てるのが安全です。

XSS安全なハイライト(mark でラップ)
function highlight(element, target) {
  if (!target) return; // 空文字だと indexOf が進まず無限ループになるため弾く
  const text = element.textContent;
  element.textContent = ""; // 中身をクリア
  let i = 0;
  let idx;
  while ((idx = text.indexOf(target, i)) !== -1) {
    // ヒット前のテキスト(文字列として安全に追加)
    element.append(text.slice(i, idx));
    // ヒット部分を <mark> で囲む
    const mark = document.createElement("mark");
    mark.textContent = target;
    element.append(mark);
    i = idx + target.length;
  }
  element.append(text.slice(i)); // 残り
}

// <p id="target">JavaScriptでJavaを学ぶ</p>
highlight(document.getElementById("target"), "Java");

モダンな方法:CSS Custom Highlight API

DOMを書き換えずにハイライトできる新しいAPIです。RangeHighlight に登録し、CSSの ::highlight() 擬似要素で見た目を指定します。元のDOM構造を壊さないのが利点です。

Custom Highlight API(JS)
const el = document.getElementById("target");
const node = el.firstChild;

const range = new Range();
range.setStart(node, 0);
range.setEnd(node, 4);

const highlight = new Highlight(range);
CSS.highlights.set("search-result", highlight); // 名前を付けて登録
Custom Highlight API(CSS)
::highlight(search-result) {
  background-color: #fef08a;
  color: #000;
}
対応ブラウザに注意:CSS Custom Highlight API は比較的新しい機能です(Chrome / Edge 105+、Safari 17.2+、Firefox 140+ 〔2025年〕)。対応状況は変わるため、導入前に最新の対応表(MDN / Can I use)を確認し、未対応環境向けには <mark> ラップなどのフォールバックを用意してください。

エッジケースと注意点

  • 範囲外の値setSelectionRange() は範囲を自動で丸めますが、Range は範囲外だと例外になるため、Math.min / Math.max で文字数内に収める
  • 子要素を含む要素firstChild がテキストノードとは限らない。複数ノードにまたがる選択は開始・終了ノードを個別に指定する
  • focus 忘れ:input の選択は focus() しないと画面に反映されないことがある
  • 選択の解除:通常要素は getSelection().removeAllRanges()、input は setSelectionRange(0, 0)blur()
旧IEの document.body.createTextRange() は不要です。Internet Explorer はサポートが終了しており、現在のブラウザはすべて Selection API に対応しています。

方法の使い分け

やりたいこと 対象 使う方法
範囲を選択状態にする input / textarea setSelectionRange(start, end)
範囲を選択状態にする p / div など Selection API + Range
反転させず色を付ける 任意の要素 <mark> ラップ / Custom Highlight API
選択中の文字列を取得 ページ全体 getSelection().toString()
選択中の文字列を取得 input / textarea value.substring(selectionStart, selectionEnd)

実用例:入力欄を全選択して自動コピー

クーポンコードやURLを「クリックで全選択&コピー」させる定番パターンです。コピーの詳細はクリップボードにテキストをコピーする方法も参照してください。

全選択して自動コピー
async function selectAndCopy(input) {
  input.focus();
  input.select(); // = setSelectionRange(0, value.length)

  // モダンな Clipboard API(推奨)
  try {
    await navigator.clipboard.writeText(input.value);
    console.log("コピーしました");
  } catch (e) {
    // 古い環境のフォールバック(非推奨だが互換用)
    document.execCommand("copy");
  }
}

const code = document.getElementById("coupon");
code.addEventListener("click", () => selectAndCopy(code));

よくある質問(FAQ)

Qテキストを「選択」するのと「抽出」するのは違うのですか?
A違います。選択は画面上で範囲を反転させる(ユーザーに見える)操作で、setSelectionRange() や Selection API を使います。抽出は部分文字列を値として取り出すだけで、slice() / substring() を使います。目的に合わせて選びましょう。
Qinput の一部だけを選択するにはどうすればいいですか?
Ainput.focus() してから input.setSelectionRange(開始, 終了) を呼びます。全選択なら input.select() が簡単です。選択中の文字列は input.value.substring(input.selectionStart, input.selectionEnd) で取得できます。
Q選択を解除するにはどうすればいいですか?
A通常要素は window.getSelection().removeAllRanges() で解除できます。入力欄は input.setSelectionRange(0, 0) でカーソルを先頭に戻すか、input.blur() でフォーカスを外します。
QIE向けの createTextRange は今でも必要ですか?
A不要です。Internet Explorer はサポート終了済みで、現在のブラウザ(Chrome・Firefox・Safari・Edge)はすべて Selection API に対応しています。旧IE分岐を削除するとコードが大幅にシンプルになります。

まとめ

JavaScriptで指定範囲の文字列を選択・ハイライトする方法のポイントを整理します。

  • input / textarea は setSelectionRange(start, end)(+focus()、全選択は select()
  • 通常要素は document.createRange()Selection(範囲は文字数内に丸める)
  • 反転させず色付けは <mark> ラップ(textContent でXSS対策)か CSS Custom Highlight API
  • 選択中テキストは getSelection().toString() / input は selectionStartselectionEnd
  • 旧IEの createTextRange は不要

関連として、部分文字列を取り出したいだけなら開始位置と文字数を指定して取得する方法、特定文字の前後を取り出すなら直前の1文字直後の1文字の抽出記事もあわせてご覧ください。