HOW TO: Where’s the text cursor? 🧐

Finding the text input cursor position with JavaScript

Jhey Tompkins
5 min readOct 8, 2015

--

A rather specific scenario here. But, how do you get the location of the cursor in a textarea? or an input? There is no straightforward method or property that can you can utilise. You can get selection indexes but these don’t give you the actual cursor location.

For those in camp TL;DR; do some trickery 🐇 by cloning the input and getting the position of the appended span. Here’s a demo! 🎉

Why?

Use cases where you need to show some custom UI at the exact location where the user is interacting. Popular examples include type aheads such as those for Github issues and Twitter hashtags. Or interactive tooltips likes those on the Medium WYSIWYG editor.

How?

The concept is actually pretty simple.

  1. Create a replica element of our textarea/input with near identical styling.
  2. Generate a substring of the textarea/input text content up to the point of the caret.
  3. Populate the replica element with that substring.
  4. Append a span element that contains the rest of the content.
  5. Append the replica element to the DOM

The position of the cursor is the position of the appended span 💡 Once we have the position of the span, we need to remove the replica element from the DOM. Note, the position of the span will be relative to the replica element. To get the absolute positioning on the page of the cursor we will also need to account for the location of the input/textarea. This is critical so that we don’t have to start wrapping our input elements and allows us to append our custom UI to the document.body 👍

This is the foundation for finding the cursor position. We can refer to it as the foundation cursor position. It does not consider potential scroll position, custom styling or our desired behavior.

Those calculations are best made to the obtained foundation cursor position.

Highlighting some text selection you could show editing tools etc.

For example, you may want to show custom UI beneath the cursor or center aligned above the cursor. In both use cases, you will need the foundation cursor position before anything else. We will look at different implementations below.

Code

So how does that code look for obtaining the foundation cursor position? 🤓

Pretty much like that 😉

So what’s happening there?

We’ve gone over the basic concept in “How?” but let’s walk through what’s happening;

  1. Pass the input/textarea along with the selection index as params to our getCursorXY method
  2. Create a replica div and copy the styling of our input by looping over the returned Object from getComputedStyle
  3. Fill that replica div with a substring of text content up until the selection index
  4. Create a span element and give it the text content of the remaining text content not included in the substring
  5. Append that span to the replica div
  6. Append that replica div to the DOM
  7. Obtain the location of the cursor 🎉
  8. Remove the replica element from the DOM
  9. Return the text cursor position accounting for the input position on the page 👍

Real scenarios

Cool, but how can we use this in real scenarios and how does the HTML work, can I just use this on an a plain input/textarea? 🤔

Yes! You can. Using the getCursorXY method against your input will give you the correct cursor location. It is then up to you what you do with the location.

Showing the cursor position on input and click

Let’s walk through one of the demo scenarios.

The desired behavior is that whenever we type or click, there will be an indicator showing the cursor.

So, on input and click we need to append a marker element to the document body if there isn’t one. We also need to calculate the correct position for that marker on every input or click. As a bonus, if we click off of the input, we want the marker to disappear.

This is just a basic demo, it’s not polished 💍 by any means 😅

The important things to take notice of here is what we do with the returned cursor position for our input.

In this scenario, we get the foundation cursor position first. But then we account for any custom styling and any scrolling that may have happened. Using Math.min we can ensure that there is a limit on the markers position in certain directions. Consider the left position. We don’t want the marker to go any further left than the furthest right of the input minus any padding so we limit that. In the demo, I’ve applied a basic position to the marker and then offset the indicator using basic CSS transforms 🤓

As an added bonus, when we create the marker, we add an event listener to the document.body to listen for clicks. This is so that when we click off of the input the marker can be removed from the DOM.

That is one basic scenario we can use our obtained cursor position in. See the demo for other possible use cases such as type aheads and selection highlighting.

An example type ahead triggered by a special character

Wrapping up

Not the most common article topic. But, an interesting problem with an interesting solution that I felt was worthy of sharing.

Be sure to check out the demo and code 🤓

Hopefully this can help you out if you come across the same problem. There may indeed be better ways to solve this and if you find one I’d certainly like to see it 👍 😃

As always, any questions or suggestions, please feel free to leave a response or tweet me 🐦!

--

--