Weekend coding: Add a character counter as the background of a textarea with JavaScript

Tags:

Have you ever filled a textarea on a page, which had a limit to how many characters you could type into it? Or maybe you are a Twitter user, and as you know, Twitter only displays 140 characters of your tweets.


(Not an actual textarea)

The other day I was thinking of this: How to effectively communicate how many characters you can type into a box, and have it look good. As I got the idea from Twitter, I thought what various Twitter clients had: Just a normal counter on the side of the textbox. But then I had a brilliant idea..

Add the number counter as the background of the textarea! Perhaps someone has done this before, but I wanted to give it a shot anyway. Here I’ll show you how to do that in a “progressive” manner, so you will still keep a normal textarea if it doesn’t work out.

The basic idea

This is actually not a very complex trick. We’ll have some HTML markup, with a textarea in it. Then, we will include some JavaScript code that modifies the markup, so that we have a div with a character counter under the textarea, making it look like the counter is the background of the textbox.

By using CSS, the background of the textarea can be made transparent to allow the div behind it to show. Using some more CSS, the counter in the div can be resized to show up about the same size as the box itself.

Coding it

To keep the example simple, we’ll create a basic HTML document and put both styles and scripts in the markup. You will want to separate them in “real” projects, though.

<html>
 <head>
  <script type="text/javascript">
  </script>
  <style type="text/css">
  </style>
 </head>
 <body>
  <textarea id="text"></textarea>
 </body>
</html>

A very simple HTML document with a textarea. Now, let’s add the scripts to give us the counter. Insert the following into the script element:

//We want this to run as soon as the page has loaded
window.onload = function() {
  //Character limit
  var limit = 140; 
 
  //the div to contain the background and the textarea
  var div = document.createElement('div');
  div.className = 'charcounter';
 
  //Append the div into the document before the textarea, so that when we
  //remove the textarea, it can be inserted inside the div and it'll look like it never moved.
  var txt = document.getElementById('text');
  txt.parentNode.insertBefore(div, txt);
 
  //this will contain the background numbers
  var counter = document.createElement('div');
  div.appendChild(counter);
  counter.innerHTML = limit;
 
  //Add both keypress and keydown handlers to make sure the event always fires
  txt.onkeypress = txt.onkeydown = function() {
    //Calculate how many chars the user has remaining
    var len = limit - txt.value.length;
    if(len < 0) {
      counter.className = 'negative';
    }
    else {
      counter.className = '';
    }
 
    counter.innerHTML = len;
  };
 
  txt.parentNode.removeChild(txt);
  div.appendChild(txt);
}

After adding the script, you should see a counter above the textarea, which changes every time you write something in the box.

The reason we added both onkeypress and onkeydown listeners is that some events, such as copy pasting text into the box or highlighting text and deleting it, won’t fire the other event properly. By adding both of the events, we make sure the counter always keeps up to date. You could possibly optimize this by doing a check whether either of the events already fired, to make sure the code doesn’t run twice unnecessarily.

Adding styles

Now that we have the code in place, we need to adjust the CSS styles to make it look like in the image in the beginning of the post.

Add the following to the style element:

/* The position of the parent is made relative so 
   that absolutely positioned elements take their location from this */
.charcounter {
  position: relative;
  width: 350px;
  height: 100px;
}
 
/* Make both the counter div and the textarea inside the 
   div bigger and show up on top of each other by placing
   them on top left corner with absolute positioning */
.charcounter * {
  width: 350px;
  height: 100px;
  position: absolute;
  top: 0;
  left: 0;
  background: transparent;
}
 
/* Modify the counter div's font to show up in the middle
   and with bigger letters */
.charcounter div {
  color: silver;
  font-family: Arial;
  font-size: 550%;
  font-weight: bold;
  text-align: center;
  line-height: 100px;
  vertical-align: middle;
  opacity: 0.5;
}
 
/* Finally, we want the counter to change color when it's negative */
.charcounter div.negative {
  color: red;
}

After adding these styles, the box should spring to life and look much better!

Conclusion

I think this is a useful way to indicate how many characters you can type in a box. If you have a hard limit on the characters, you should use the maxlength property in the textarea, so that in the event the JS code won’t run, the browser itself should interpret the maxlength and stop the user from typing too many characters.

Bear in mind the code shown here is just an example. It might be a good idea to encapsulate it into a proper object, instead of just sticking it straight into the onload handler.

You can see this in action here. Code and styles tested to work in Opera 10, Firefox 3.5, IE 8 on Windows 7