JS Character Countdown

Hi, i am trying to find a good JS character countdown script that i can use to count down the characters remaining in a text area field that i am using on my site.

I have done a lot of searching on google but a lot of them seem to have very long scripts and others scripts are over 6 years ago.

Can someone recommend a good, robust character countdown timer that works very well and does not require a lot of resources when it is running. I was hoping to find something similar to the twitter script (please see below)

Here’s a simple one that I whipped together just now.


<html>
<head>
</head>
<body>
<textarea id="comments"></textarea>
<script>
document.getElementById('comments').onkeyup = characterCount;

function characterCount() {
    var container = this.nextSibling;
    if (!container || container.className !== 'counter') {
        container = document.createElement('div');
        container.className = 'counter';
        this.parentNode.insertBefore(container, this.nextSibling);
    }
    container.innerHTML = this.value.length;
}
</script>
</body>
</html>

Wow, cool, thanks… that is a nice small script… is it possible to change it so that it counts down from 110 characters… i can pay you something small via paypal if it is required, thanks for your help so far…

Yes indeed. This is where a config to allow for different uses can occur, for example:


characterCount({
    target: document.getElementById('comments'),
    direction: 'down',
    max: 110
});

Here’s the characterCount script, which has grown to handle several different types of situations now.


function characterCount(config) {
    var counter = {
        defaultConfig: {
            target: document.getElementById('counter'),
            showOnInit: true,
            direction: 'up', // 'up' or 'down'
            max: Number.MAX_VALUE,
            preventOverrun: true,
            message: 'Please enter less characters'
        },
        showCount: function () {
            var container = config.target.counter,
                count = count = this.value.length,
                hasError = false;
            if (!container) {
                container = counter.getContainer.call(this, container);
                config.target.counter = container;
            }
            container.className = '';
            if (count > config.max && config.preventOverrun) {
                this.value = this.value.substr(0, config.max);
            } else {
                if (count > config.max) {
                    hasError = true;
                }
                if (config.direction === 'down') {
                    count = config.max - count;
                }
                container.innerHTML = count;
                if (hasError) {
                    container.className = 'error';
                    counter.showError(container, config.message);
                }
            }
        },
        showError: function (container, message) {
            var div = container.lastChild;
            if (div.nodeName !== 'DIV') {
                div = document.createElement('div');
                container.appendChild(div);
            }
            while (div.hasChildNodes()) {
                div.removeChild(div.firstChild);
            }
            if (!message.length) {
                container.removeChild(div);
            } else {
                div.appendChild(document.createTextNode(message));
            }
        },
        getContainer: function (container) {
            var newContainer;
            if (!container || container.className !== 'counter') {
                newContainer = document.createElement('div');
                newContainer.className = 'counter';
                this.parentNode.insertBefore(newContainer, container);
                return newContainer;
            }
            return container;
        }
    },
        prop;
    for (prop in counter.defaultConfig) {
        if (counter.defaultConfig.hasOwnProperty(prop)) {
            if (config[prop] === undefined) {
                config[prop] = counter.defaultConfig[prop];
            }
        }
    }
    config.target.onkeyup = counter.showCount;
    if (config.showOnInit) {
        config.target.onkeyup();
    }
    return true;
}

Cool, thanks for your help, this is excellent

Also, i showed a friend the initial code that you suggested and he altered it to this:

<html>
<head>
</head>
<body>
<textarea id=“comments”></textarea>
<script>
document.getElementById(‘comments’).onkeyup = characterCount;

function characterCount() {
var intMaxCount = 30;
var container = this.nextSibling;
if (!container || container.className !== ‘counter’) {
container = document.createElement(‘div’);
container.className = ‘counter’;
this.parentNode.insertBefore(container, this.nextSibling);
}
container.innerHTML = ("Number of characters left : " + (intMaxCount - this.value.length));
}
</script>
</body>
</html>

Now i am confused with which script to use… which one would you recommend

My code is useful if you want it to be capable of being able to fit many different needs.
Your friends code is smaller because it does ply want you require, and nothing else.

I’d recommend that you go with the code from your friend, if you think that you won’t ever need to change how the counter behaves.

Ok, thanks Paul. Can i ask one final question, what other ways does your code handle the counter, as in controlling “how the counter behaves”, thanks again for all your help, much appreciated :wink:

It can count up, or count down. You can set a max value so that when counting down it will countdown from a certain number. You can tell it whether you want the counter to be displayed at first, or only after some text has been entered. It can be told to prevent an overrun, so that it’s not possible to enter in more than the set max number of characters. You can disable the overrun so that counting down results in going to negative numbers, or counting up results in exceeding the max. It also sets the class to ‘error’ so that you can provide visual feedback about such overruns too.

It can do quite a bit.

Wow cool, i will definitely use this for some other project but i think your first script will be fine for now, thanks again for your help Paul…

Here’s some additional info that will help.

The target property is required, and that’s as minimal as it might be.


characterCount({
    target: document.getElementById('default')
});

Here are all of the default properties for the counter:


characterCount({
    target: document.getElementById('counter'),
    showOnInit: true,
    direction: 'up',
    max: Number.MAX_VALUE,
    preventOverrun: false,
    message: 'Please enter less characters'
});

You can have the counter remain hidden until something is typed:


characterCount({
    target: document.getElementById('dontShow'),
    showOnInit: false
});

To have a max of 10 characters, you would use this:


characterCount({
    target: document.getElementById('maxChars'),
    max: 10
});

You can style the error class, so that you can provide a visual indication of what’s going on:


.error {
    color: red;
}
.error div {
    display: inline;
    margin-left: 1em;
}


characterCount({
    target: document.getElementById('dontPrevent'),
    max: 10,
    preventOverrun: false
});

Or if you don’t want the error message to appear:


characterCount({
    target: document.getElementById('dontPrevent'),
    max: 10,
    preventOverrun: false,
    message: ''
});

You can have it count down from a certain maximum too:


characterCount({
    target: document.getElementById('countingDown'),
    direction: 'down',
    max: 10
});

And you can have the counter go in to negative numbers too, by disabling the overrun prevention.


characterCount({
    target: document.getElementById('countingDownOverrun'),
    direction: 'down',
    max: 10,
    preventOverrun: false
});

Cool, thanks a million for this Paul :wink: