JavaScriptで「ページ上のテキストの一部を選択状態にしたい(青く反転させたい・ハイライトしたい)」という場面があります。入力欄の一部を選択してコピーさせたり、検索ヒット箇所を強調表示したりするケースです。
選択する対象が <input> / <textarea> なのか、<p> や <div> などの通常要素なのかで使うAPIが変わります。この記事では setSelectionRange()・Selection API+Range・ハイライト表示・選択テキストの取得まで、ブラウザ対応とあわせて解説します。
el.setSelectionRange(start, end)、通常要素(p / div など)は Selection API + Range、「反転させず色だけ付けたい」なら <mark> でラップするか CSS Custom Highlight API を使います。input / textarea の範囲を選択する(setSelectionRange)
フォーム部品では標準メソッド setSelectionRange(開始, 終了) が使えます。選択を画面に見せるには先に focus() しておきます。
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 オブジェクトに追加します。
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 で組み立てるのが安全です。
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です。Range を Highlight に登録し、CSSの ::highlight() 擬似要素で見た目を指定します。元のDOM構造を壊さないのが利点です。
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); // 名前を付けて登録
::highlight(search-result) {
background-color: #fef08a;
color: #000;
}
<mark> ラップなどのフォールバックを用意してください。エッジケースと注意点
- 範囲外の値:
setSelectionRange()は範囲を自動で丸めますが、Range は範囲外だと例外になるため、Math.min/Math.maxで文字数内に収める - 子要素を含む要素:
firstChildがテキストノードとは限らない。複数ノードにまたがる選択は開始・終了ノードを個別に指定する - focus 忘れ:input の選択は
focus()しないと画面に反映されないことがある - 選択の解除:通常要素は
getSelection().removeAllRanges()、input はsetSelectionRange(0, 0)やblur()
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)
setSelectionRange() や Selection API を使います。抽出は部分文字列を値として取り出すだけで、slice() / substring() を使います。目的に合わせて選びましょう。input.focus() してから input.setSelectionRange(開始, 終了) を呼びます。全選択なら input.select() が簡単です。選択中の文字列は input.value.substring(input.selectionStart, input.selectionEnd) で取得できます。window.getSelection().removeAllRanges() で解除できます。入力欄は input.setSelectionRange(0, 0) でカーソルを先頭に戻すか、input.blur() でフォーカスを外します。まとめ
JavaScriptで指定範囲の文字列を選択・ハイライトする方法のポイントを整理します。
- input / textarea は
setSelectionRange(start, end)(+focus()、全選択はselect()) - 通常要素は
document.createRange()+Selection(範囲は文字数内に丸める) - 反転させず色付けは
<mark>ラップ(textContentでXSS対策)か CSS Custom Highlight API - 選択中テキストは
getSelection().toString()/ input はselectionStart・selectionEnd - 旧IEの
createTextRangeは不要
関連として、部分文字列を取り出したいだけなら開始位置と文字数を指定して取得する方法、特定文字の前後を取り出すなら直前の1文字・直後の1文字の抽出記事もあわせてご覧ください。
