How do I get the index of the text caret in an input?
Get caret position in HTML input?
Asked Answered
<!doctype html>
<html>
<head>
<meta charset = "utf-8">
<script type = "text/javascript">
window.addEventListener ("load", function () {
var input = document.getElementsByTagName ("input");
input[0].addEventListener ("keydown", function () {
alert ("Caret position: " + this.selectionStart);
// You can also set the caret: this.selectionStart = 2;
});
});
</script>
<title>Test</title>
</head>
<body>
<input type = "text">
</body>
</html>
Well, the listener should be registered on keyup and it does not handle new lines (textarea), but this does exactly what was asked for in modern browsers. –
Hakenkreuz
You also need the input's selectionDirection to get the caret position whenever selectionDirection is backward i.e. you make a selection left-ward in the textbox so that selectionStart is the caret, but when selectionDirection is forward the caret will be at selectionEnd. –
Lawannalawbreaker
if you use
keydown
, then you need to adjust the output based on whether or not the key
is an arrow key –
Phylogeny @Hakenkreuz is there any practical way to detect or anticipate the actual selection on the
keydown
event if one or more characters is highlighted or selected? just realized selectionStart !== selectionEnd
should do the trick –
Phylogeny @Phylogeny yes that would work. Keep in mind, that the currently pressed key will not be included in your selection (for example if you select using shift+arrows). If you want to get the final selection use the "keyup" event. –
Hakenkreuz
@Hakenkreuz yep i was aware of that. thanks for pointing it out nonetheless! –
Phylogeny
The following will get you the start and end of the selection as character indices. It works for text inputs and textareas, and is slightly complicated because of IE's strange handling of line breaks.
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
var textBox = document.getElementById("textBoxId");
textBox.focus();
alert( getInputSelection(textBox).start );
@NadavB: Are you sure the value you're passing into the function is a DOM input or textarea element? –
Arguello
@TimDown it's content editable div. Should it work on it too? –
Invalidate
@NadavB: No. Here's a rough equivalent for contenteditable: https://mcmap.net/q/83470/-get-a-range-39-s-start-and-end-offset-39-s-relative-to-its-parent-container –
Arguello
There is now a nice jQuery plugin for this: Caret plugin
Then you can just call $("#myTextBox").caret();
We had used something like this for an old javascript application, but I haven't tested it in a couple years:
function getCaretPos(input) {
// Internet Explorer Caret Position (TextArea)
if (document.selection && document.selection.createRange) {
var range = document.selection.createRange();
var bookmark = range.getBookmark();
var caret_pos = bookmark.charCodeAt(2) - 2;
} else {
// Firefox Caret Position (TextArea)
if (input.setSelectionRange)
var caret_pos = input.selectionStart;
}
return caret_pos;
}
Seems to be a consistent 21 characters off in IE. With an adjustment it seems fine there, but then is inaccurate in FF. http://jsfiddle.net/zqNpV/ –
Tophet
Get coordinates (css: left:x , top:y
) of the current caret position in order to position an element (e.g. show tooltip at caret position)
function getCaretCoordinates() {
let x = 0,
y = 0;
const isSupported = typeof window.getSelection !== "undefined";
if (isSupported) {
const selection = window.getSelection();
// Check if there is a selection (i.e. cursor in place)
if (selection.rangeCount !== 0) {
// Clone the range
const range = selection.getRangeAt(0).cloneRange();
// Collapse the range to the start, so there are not multiple chars selected
range.collapse(true);
// getCientRects returns all the positioning information we need
const rect = range.getClientRects()[0];
if (rect) {
x = rect.left; // since the caret is only 1px wide, left == right
y = rect.top; // top edge of the caret
}
}
}
return { x, y };
}
demo: https://codesandbox.io/s/caret-coordinates-index-contenteditable-9tq3o?from-embed
Working example of getting cursor point in text box:
function textbox()
{
var ctl = document.getElementById('Javascript_example');
var startPos = ctl.selectionStart;
var endPos = ctl.selectionEnd;
alert(startPos + ", " + endPos);
}
© 2022 - 2024 — McMap. All rights reserved.