I've just written a jQuery plug-in to do this that works in all major browsers. It uses keydown and keypress to bind event listeners to a set of of elements. The event listeners prevent the default behaviour for the Tab key, while the keydown listener also manually inserts a tab character at the caret/selection.
Here it is in action: http://www.jsfiddle.net/8segz/
Here's an example use:
$(function() { $("textarea").allowTabChar(); });
Here's the plug-in code:
(function($) { function pasteIntoInput(el, text) { el.focus(); if (typeof el.selectionStart == "number") { var val = el.value; var selStart = el.selectionStart; el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd); el.selectionEnd = el.selectionStart = selStart + text.length; } else if (typeof document.selection != "undefined") { var textRange = document.selection.createRange(); textRange.text = text; textRange.collapse(false); textRange.select(); } } function allowTabChar(el) { $(el).keydown(function(e) { if (e.which == 9) { pasteIntoInput(this, "\t"); return false; } }); // For Opera, which only allows suppression of keypress events, not keydown $(el).keypress(function(e) { if (e.which == 9) { return false; } }); } $.fn.allowTabChar = function() { if (this.jquery) { this.each(function() { if (this.nodeType == 1) { var nodeName = this.nodeName.toLowerCase(); if (nodeName == "textarea" || (nodeName == "input" && this.type == "text")) { allowTabChar(this); } } }) } return this; } })(jQuery);