Find out the 'line' (row) number of the cursor in a textarea

You would want to use selectionStart to do this.

<textarea onkeyup="getLineNumber(this, document.getElementById('lineNo'));" onmouseup="this.onkeyup();"></textarea>
<div id="lineNo"></div>

<script>

    function getLineNumber(textarea, indicator) {

        indicator.innerHTML = textarea.value.substr(0, textarea.selectionStart).split("\n").length;
    }

</script>

This works when you change the cursor position using the mouse as well.


This is tough because of word wrap. It's a very easy thing to count the number of line breaks present, but what happens when the new row is because of word wrap? To solve this problem, it's useful to create a mirror (credit: github.com/jevin). Here's the idea:

  1. Create a mirror of the textarea
  2. Send the content from the beginning of the textarea to the cursor to the mirror
  3. Use the height of the mirror to extract the current row

On JSFiddle

jQuery.fn.trackRows = function() {
    return this.each(function() {

    var ininitalHeight, currentRow, firstIteration = true;

    var createMirror = function(textarea) {
        jQuery(textarea).after('<div class="autogrow-textarea-mirror"></div>');
        return jQuery(textarea).next('.autogrow-textarea-mirror')[0];
    }

    var sendContentToMirror = function (textarea) {
        mirror.innerHTML = String(textarea.value.substring(0,textarea.selectionStart-1)).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br />') + '.<br/>.';
        calculateRowNumber();
    }

    var growTextarea = function () {
        sendContentToMirror(this);
    }

    var calculateRowNumber = function () {
        if(firstIteration){
            ininitalHeight = $(mirror).height();
            currentHeight = ininitalHeight;
            firstIteration = false;
        } else {
            currentHeight = $(mirror).height();
        }
        // Assume that textarea.rows = 2 initially
        currentRow = currentHeight/(ininitalHeight/2) - 1;
        //remove tracker in production
        $('.tracker').html('Current row: ' + currentRow);
    }

    // Create a mirror
    var mirror = createMirror(this);

    // Style the mirror
    mirror.style.display = 'none';
    mirror.style.wordWrap = 'break-word';
    mirror.style.whiteSpace = 'normal';
    mirror.style.padding = jQuery(this).css('padding');
    mirror.style.width = jQuery(this).css('width');
    mirror.style.fontFamily = jQuery(this).css('font-family');
    mirror.style.fontSize = jQuery(this).css('font-size');
    mirror.style.lineHeight = jQuery(this).css('line-height');

    // Style the textarea
    this.style.overflow = "hidden";
    this.style.minHeight = this.rows+"em";

    var ininitalHeight = $(mirror).height();

    // Bind the textarea's event
    this.onkeyup = growTextarea;

    // Fire the event for text already present
    // sendContentToMirror(this);

    });
};

$(function(){
    $('textarea').trackRows();
});