xinglinkedinenvelopebubblesgoogleplusfacebooktwitterfeedgithub

Adding tab support to textareas

30th January 2014 | by Adam Beres-Deak | javascript, browser

Have you ever wondered how is it possible to support tabs in a textarea? Normally when you press the tab key, the focus jumps to the next element. But with some JavaScript 'magic' it's possible to indent or unindent the text.

The code detects when the user presses TAB or SHIFT+TAB - the current line gets indented or unindented. Source code for the example can be found here: gist.github.com/bdadam/8721698.

<!doctype html>
<html>
<head>
    <meta name="charset" content="utf-8"/>
    <title></title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="author" content="Adam Beres-Deak"/>
    <meta name="viewport" content="width=device-width"/>
    <style>
        body {
            padding: 40px;
        }
        textarea {
            width: 100%;
            height: 350px;
            font-family: CourierNew, Courier;
        }
    </style>
</head>
<body>
    <textarea id="tx"></textarea>
    <script>
    function enableTab(id) {
        var shiftPressed = false;
        var ctrlPressed = false;
        var tabChar = '    ';

        function checkSpecialKeys(e) {
            switch(e.keyCode) {
                case 16:
                    shiftPressed = !shiftPressed;
                    break;
                case 17:
                    ctrlPressed = !ctrlPressed;
            }
        }

        document.addEventListener('keydown', checkSpecialKeys);
        document.addEventListener('keyup', checkSpecialKeys);

        function addTab(textarea) {
            // caching some values, because they are changing as text changes
            var value = textarea.value,
                start = textarea.selectionStart,
                end = textarea.selectionEnd;

            // adding tab character to actual cursor position
            textarea.value = value.substring(0, start) + tabChar + value.substring(end);

            // putting cursor back to its original position
            textarea.selectionStart = textarea.selectionEnd = start + tabChar.length;
        }

        function removeTab(textarea) {
            var curPos = textarea.selectionStart,
                lines = textarea.value.split('\n'),
                newValue = '',
                done = false,
                cnt = 0;

            for (var i = 0, l = lines.length; i < l; i++) {
                // iterating through each line
                var line = lines[i];
                cnt += line.length;
                if (cnt >= curPos && !done) {
                    // cursor is in this line
                    var newLine = line.replace(new RegExp('^' + tabChar, ''), '');

                    if (newLine !== line) {
                        // there was a tab at the beginning of the line, replace was succesfull, cursor must be moved backwards some
                        line = newLine;
                        curPos -=tabChar.length;
                    }

                    done = true; // only one substitution per run
                }

                newValue += line + '\n';
            }

            // setting new value
            textarea.value = newValue;

            // putting cursor back to its original position
            textarea.selectionStart = textarea.selectionEnd = curPos;
        }

        var textArea = document.getElementById(id);
        textArea.addEventListener('keydown', function(e) {
            if (e.keyCode === 9) {

                if (!shiftPressed) {
                    addTab(this);
                } else {
                    removeTab(this);
                }

                return false; // preventing losing focus
            }
        });
    }

    enableTab('tx');
    </script>
</body>

by Adam Beres-Deak

| Share | Tweet | Share | Share

Latest blog posts

Displaying icons with custom elements 14th October 2015

Plain JavaScript event delegation 26th January 2015

After the first year of blogging - what happened on my blog in 2014? 1st January 2015

Better webfont loading with using localStorage and providing WOFF2 support 18th December 2014

Worth watching: Douglas Crockford speaking about the new good parts of JavaScript in 2014 20th October 2014