How to add character count to any textarea in JavaScript

How to add character count to any textarea in JavaScript

If you are building a user entry form of any kind, you often times want to limit the number of characters that a user is allowed to enter into any input area. You can set the maxlength attribute of any input or textarea in order to do so.

<textarea maxlength='100'></textarea>

There is no built in UI/UX element currently however that will show the user the number of characters remaining or that have been used up.

So here is a small script that will do just that for you. Given any input or textarea in your web forms, you can automatically add a character counter by adding a single class to the element.

The HTML

Copy the following HTML into your favorite coding editor, like VS Code in order to get started. Notice the structure of the elements and the class name's given to each.

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]>      <html class="no-js"> <!--<![endif]-->
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="">
        
        <style>
            .charcount{
                position: relative;
                background: #f2f2f2;
                padding: 40px;
                border-radius: 10px;
                width: 50%;
                margin: 40px auto;
                box-sizing: border-box;
            }

            .charcount textarea{
                width: 100%;
                border-radius: 10px;
                padding: 10px;
                border:solid 1px #aaa;
                display:block;
                box-sizing:border-box;
                height: 100px;
            }

            .charcount::after{
                content: attr(data-charcount) " chars";
                position: absolute;
                bottom: 20px;
                font-size: 10pt;
                color: #777;
            }
        </style>
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->
        <div class='charcount'>
            <textarea></textarea>
        </div>

        <div class='charcount'>
            <textarea></textarea>
        </div>

        <div class='charcount'>
            <textarea></textarea>
        </div>
        
        <script>
            function loadCharCounts(){
                let elements = Array.from(document.getElementsByClassName('charcount'));
                elements.forEach(item => {
                    let textarea = item.querySelector('textarea');
                    textarea.addEventListener('keyup', function(e){
                        item.dataset.charcount = this.value.length;
                    });
                    item.dataset.charcount = '0';
                });
            }

            window.addEventListener('load', function(){
               loadCharCounts(); 
            });
        </script>
    </body>
</html>

Let's break everything down, starting with the DOM elements and ending with the JavaScript event handler.

If you notice above, each <textarea> element is enclosed within a parent <div> element.

<div class='charcount'>
    <textarea></textarea>
</div>

The reason for that is that I am using the ::after CSS pseudoclass in order to render the actual counter onto the page. The <textarea> element does not currently support use of ::after, which is why I've wrapped it in a parent <div>.

The CSS

Let's take a closer look at the actual CSS properties, particularly the ::after pseudo class

.wordcount::after{
    content: attr(data-charcount) " chars";
    position: absolute;
    bottom: 20px;
    font-size: 10pt;
    color: #777;
}

This is where the actual character count is rendered onto the page. For that to happen, you have to set the content property of the ::after pseudo class to the data-charcount attribute that each textarea will contain.

And lastly, the counter is positioned absolutely below the textarea in question. This is a style decision that you can make yourself, though typically you find character counters near one of the two bottom corners.

The JavaScript

The most common UI/UX used for a word count is essentially one that updates the count with every keystroke.

Let's take a look at the loadCharCounts() in more detail.

function loadCharCounts(){
      let elements = Array.from(document.getElementsByClassName('charcount'));
      elements.forEach(item => {
        let textarea = item.querySelector('textarea');
        textarea.addEventListener('keyup', function(e){
            item.dataset.charcount = this.value.length;
        });
        item.dataset.charcount = '0';
    });
}

The first thing that we need to do is to locate all elements on the page with the class of charcount. This again will refer to the <div> elements in which each <textarea> resides in.

The Array.from method is used to convert those found elements into an array object so that we can iterate through them.

You can then loop through all of these items using the forEach method of the Array class. The main purpose with looping through all charcount elements is to attach the keyup event listener to the child textarea elements.

On each keyup event, the charcount dataset property will be updated to the length of the given textarea value.

The CSS content property is then responsible for updating the actual counter on the page.

Demo

And lastly, here is a running example of the functionality.

Typically you don't want to rely too much on your CSS properties in order to render DOM elements on your page, as this does go against the principle of seperation of concerns. But for small tasks, such as this one, this can be a very efficient method that saves you a fair amount of code.

Walter G. author of blog post
Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.

Get the latest programming news directly in your inbox!

Have a question on this article?

You can leave me a question on this particular article (or any other really).

Ask a question

Community Comments

No comments posted yet

Add a comment