Tabbing in a textarea

2011-12-25

This always annoys me a little. You're writing a comment with some code and you want to tab. Or you're just fiddling something for yourself and need a very primitive code editor. Tabbing is going to be a major PITA. So... here's a little snippet that might come in handy.

The following snippet is a cut-and-paste solution for getting some tab magic to work in most current browsers. It allows you to regularly tab, of course, but also tab multiple lines at once as well as de-indent one tab or multiple lines. Fwiw, this is how I prefer my tabbing action when editing :)

Code:
textarea.onkeydown = function(e){
if (e.keyCode == 9) { // tab
var input = textarea.value; // as shown, `this` would also be textarea, just like e.target
var remove = e.shiftKey;
var posstart = textarea.selectionStart;
var posend = textarea.selectionEnd;
// if anything has been selected, add one tab in front of any line in the selection
if (posstart != posend) {
posstart = input.lastIndexOf('\n', posstart) + 1;
var compensateForNewline = input[posend-1] == '\n';
var before = input.substring(0,posstart);
var after = input.substring(posend-(compensateForNewline?1:0));
var selection = input.substring(posstart,posend);

// now add or remove tabs at the start of each selected line, depending on shift key state
// note: this might not work so good on mobile, as shiftKey is a little unreliable...
if (remove) {
if (selection[0] == '\t') selection = selection.substring(1);
selection = selection.split('\n\t').join('\n');
} else {
selection = selection.split('\n');
if (compensateForNewline) selection.pop();
selection = '\t'+selection.join('\n\t');
}

// put it all back in...
textarea.value = before+selection+after;
// reselect area
textarea.selectionStart = posstart;
textarea.selectionEnd = posstart + selection.length;
} else {
var val = textarea.value;
textarea.value = val.substring(0,posstart) + '\t' + val.substring(posstart);
textarea.selectionEnd = textarea.selectionStart = posstart + 1;
}

e.preventDefault(); // dont jump. unfortunately, also/still doesnt insert the tab.
}
};

Hope it helps you :)