admin管理员组

文章数量:1135640

I would like a textarea that handles a situation of pressing tab key.

In default case if you press a tab key then focus leaves the textarea. But what about the situation when user wants to type tab key in textarea?

Can I catch this event and return focus to the textarea and add a tab to a current cursor position?

I would like a textarea that handles a situation of pressing tab key.

In default case if you press a tab key then focus leaves the textarea. But what about the situation when user wants to type tab key in textarea?

Can I catch this event and return focus to the textarea and add a tab to a current cursor position?

Share Improve this question edited Mar 22, 2013 at 8:43 sergzach asked May 26, 2011 at 14:54 sergzachsergzach 6,7547 gold badges51 silver badges86 bronze badges 2
  • Possible duplicate of Use tab to indent in textarea – Pere Commented Jan 2, 2017 at 16:18
  • I reviewed some of the existing answers and they all fall short in some way (no undo, poor performance, incorrect selection after unindent). I recently wrote a small module that handles this correctly, called indent-textarea – fregante Commented Dec 15, 2019 at 21:07
Add a comment  | 

6 Answers 6

Reset to default 132

You can: http://jsfiddle.net/sdDVf/8/.


$("textarea").keydown(function(e) {
    if(e.keyCode === 9) { // tab was pressed
        // get caret position/selection
        var start = this.selectionStart;
        var end = this.selectionEnd;

        var $this = $(this);
        var value = $this.val();

        // set textarea value to: text before caret + tab + text after caret
        $this.val(value.substring(0, start)
                    + "\t"
                    + value.substring(end));

        // put caret at right position again (add one for the tab)
        this.selectionStart = this.selectionEnd = start + 1;

        // prevent the focus lose
        e.preventDefault();
    }
});

Here is a modified version of pimvdb's answer that doesn't need JQuery:

document.querySelector("textarea").addEventListener('keydown',function(e) {
    if(e.keyCode === 9) { // tab was pressed
        // get caret position/selection
        var start = this.selectionStart;
        var end = this.selectionEnd;

        var target = e.target;
        var value = target.value;

        // set textarea value to: text before caret + tab + text after caret
        target.value = value.substring(0, start)
                    + "\t"
                    + value.substring(end);

        // put caret at right position again (add one for the tab)
        this.selectionStart = this.selectionEnd = start + 1;

        // prevent the focus lose
        e.preventDefault();
    }
},false);

I tested it in Firefox 21.0 and Chrome 27. Don't know if it works anywhere else.

Good god, all previous answers failed to provide the commonly decent (i.e. for programmers) tab control.

That is, a hitting TAB on selection of lines will indent those lines, and SHIFTTAB will un-indent them.

_edited (Nov 2016): keyCode replaced with charCode || keyCode, per KeyboardEvent.charCode - Web APIs | MDN

(function($) {
  $.fn.enableSmartTab = function() {
    var $this;
    $this = $(this);
    $this.keydown(function(e) {
      var after, before, end, lastNewLine, changeLength, re, replace, selection, start, val;
      if ((e.charCode === 9 || e.keyCode === 9) && !e.altKey && !e.ctrlKey && !e.metaKey) {
        e.preventDefault();
        start = this.selectionStart;
        end = this.selectionEnd;
        val = $this.val();
        before = val.substring(0, start);
        after = val.substring(end);
        replace = true;
        if (start !== end) {
          selection = val.substring(start, end);
          if (~selection.indexOf('\n')) {
            replace = false;
            changeLength = 0;
            lastNewLine = before.lastIndexOf('\n');
            if (!~lastNewLine) {
              selection = before + selection;
              changeLength = before.length;
              before = '';
            } else {
              selection = before.substring(lastNewLine) + selection;
              changeLength = before.length - lastNewLine;
              before = before.substring(0, lastNewLine);
            }
            if (e.shiftKey) {
              re = /(\n|^)(\t|[ ]{1,8})/g;
              if (selection.match(re)) {
                start--;
                changeLength--;
              }
              selection = selection.replace(re, '$1');
            } else {
              selection = selection.replace(/(\n|^)/g, '$1\t');
              start++;
              changeLength++;
            }
            $this.val(before + selection + after);
            this.selectionStart = start;
            this.selectionEnd = start + selection.length - changeLength;
          }
        }
        if (replace && !e.shiftKey) {
          $this.val(before + '\t' + after);
          this.selectionStart = this.selectionEnd = start + 1;
        }
      }
    });
  };
})(jQuery);

$(function() {
  $("textarea").enableSmartTab();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea rows="10" cols="80">
/* Just some code to edit with our new superTab */
(function($) {
    $.fn.enableSmartTab = function() {
        $this = $(this);
        $this.keydown(function(e) {
            if ((e.charCode === 9 || e.keyCode === 9) && !e.metaKey && !e.ctrlKey && !e.altKey) {
                e.preventDefault();
            }
        }
    }
}
</textarea>

In Vanilla (Default) JS this would be:

var textareas = document.getElementsByTagName('textarea');

if ( textareas ) {
  for ( var i = 0; i < textareas.length; i++ ) {
textareas[i].addEventListener( 'keydown', function ( e ) {
  if ( e.which != 9 ) return;

  var start             = this.selectionStart;
  var end                 = this.selectionEnd;

  this.value            = this.value.substr( 0, start ) + "\t" + this.value.substr( end );
  this.selectionStart = this.selectionEnd = start + 1;

  e.preventDefault();
  return false;
});
  }
}
textarea {
   border: 1px solid #cfcfcf;
   width: 100%;
   margin-left: 0px;
   top: 0px;
   bottom: 0px;
   position: absolute;
}
<textarea>
var x = 10;
var y = 10;
</textarea>

Found this while searching google. I made a really short one that can also indent and reverse indent selections of text:

    jQ(document).on('keydown', 'textarea', function(e) {
        if (e.keyCode !== 9) return;
        var Z;
        var S = this.selectionStart;
        var E = Z = this.selectionEnd;
        var A = this.value.slice(S, E);
        A = A.split('\n');
        if (!e.shiftKey)
            for (var x in A) {
                A[x] = '\t' + A[x];
                Z++;
            }
        else
            for (var x in A) {
                if (A[x][0] == '\t')
                    A[x] = A[x].substr(1);
                Z--;
            }
        A = A.join('\n');
        this.value = this.value.slice(0, S) + A + this.value.slice(E);
        this.selectionStart = S != E ? S : Z;;
        this.selectionEnd = Z;
        e.preventDefault();
    });

Enable tabbing inside (multiple) textarea elements

Correcting @alexwells answer and enable a live demo

var textAreaArray = document.querySelectorAll("textarea");
    for (var i = textAreaArray.length-1; i >=0;i--){
        textAreaArray[i].addEventListener('keydown',function(e) {
            if(e.keyCode === 9) { // tab was pressed
                // get caret position/selection
                var start = this.selectionStart;
                var end = this.selectionEnd;

                var target = e.target;
                var value = target.value;

                // set textarea value to: text before caret + tab + text after caret
                target.value = value.substring(0, start)
                            + "\t"
                            + value.substring(end);

                // put caret at right position again (add one for the tab)
                this.selectionStart = this.selectionEnd = start + 1;

                // prevent the focus lose
                e.preventDefault();
            }
        },false);
    }
<textarea rows="10" cols="80"></textarea>
   <textarea rows="10" cols="80"></textarea>

本文标签: javascriptHow to handle lttabgt in textareaStack Overflow