DEV Community

Cover image for Creating a textarea character limit indicator
sahra πŸ’«
sahra πŸ’«

Posted on • Updated on

Creating a textarea character limit indicator

Introduction

Textareas are an essential tool of the web, allowing applications to collect additional information from users. This helps to facilitate seamless communication and interaction between users and the application.

Why is a character limit indicator important?

A character limit indicator lets the user know how many characters are allowed in the textarea as set by its maxlength attribute. This allows users to tailor their text to convey the necessary information while being conscious of how much writing space they are left with.

In this article, we will be looking at how we can implement a character limit indicator for the textarea fields in our projects.

Below is a preview of what we will be creating.

Textarea character limit preview

Now that we understand the importance of a character limit indicator, let’s dive into the implementation.

Setting up the HTML

To get started, Inside our HTML file, first we include an h1 tag with the name of our project.

<h1>Textarea character limit indicator</h1>
Enter fullscreen mode Exit fullscreen mode

Next, we create a container div to hold the textarea and progress bar.

<div id="container">
</div>
Enter fullscreen mode Exit fullscreen mode

Inside this div, we include a label and the textarea element with a maxlength property of 150 characters allowed in the text field.

<label for="txt">Type something:</label>
<textarea name="type-something" id="txt" maxlength="150" cols="30" rows="10"></textarea>
Enter fullscreen mode Exit fullscreen mode

Below the textarea field, we include the structure of our progress bar which we will be styling later on.

<div id="progress">
  <div id="progress-bar"></div>
  <p id="remaining-chars"></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Our html should look something like this now:

plain HTML structure of the textarea character limit preview

That is all for our HTML file. Next, we move into our CSS file to style the elements.

Styling the page with CSS

Inside our CSS file, apply some default page styling first.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
Enter fullscreen mode Exit fullscreen mode

Next, we style the body and h1 tag of the page.

body {
  display: grid;
  place-items: center;
  min-height: 100vh;
  padding: 10px 30px;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  background-color: #f5f5ff;
}

h1 {
  text-align: center;
  margin: 10px 0 50px;
}
Enter fullscreen mode Exit fullscreen mode

After that, we apply some styles to our container div, helping to properly align the textarea and the progress bar in the container.

#container {
  display: grid;
  background-color: white;
  border-radius: 20px;
  box-shadow: 1px 1px 12px #aaa;
  padding: 40px;
  font-size: 13px;
  margin-bottom: 70px;
}
Enter fullscreen mode Exit fullscreen mode

Next up, we style the label and texarea field along with its focus state.

label {
  font-size: 15px;
  font-weight: bold;
}

textarea {
  resize: none;
  padding: 10px;
  margin: 10px 0;
  font-family: Arial, Helvetica, sans-serif;
  letter-spacing: 1.3px;
  border-radius: 5px;
}

textarea:focus {
  outline: 1px solid rgb(14, 51, 14);
}
Enter fullscreen mode Exit fullscreen mode

Following that, we style the progress bar and the remaining-chars element, which will be used to display how many characters are left to use.

#progress {
  width: 100%;
  height: 7px;
  box-shadow: inset 1px 1px 2px #ccc;
  border: 1px solid #bbb;
  border-radius: 15px;
}

#progress-bar {
  height: 100%;
}

#remaining-chars {
  font-size: 11px;
  color: #b62020;
  margin-top: 3px;
  float: right;
  display: none;
}
Enter fullscreen mode Exit fullscreen mode

That concludes our CSS file. Now, let's delve into the exciting part: making our limit indicator functional.

Implementing the limit indicator with JavaScript

Inside our JS file, we want to first get the elements we will be working with later on.

const textarea = document.getElementById("txt");
const progressBar = document.getElementById("progress-bar");
const remChars = document.getElementById("remaining-chars");
Enter fullscreen mode Exit fullscreen mode

Next, we create the character counter function.

function charCounter(inputField) {
  // Counter logic goes in here
}
Enter fullscreen mode Exit fullscreen mode

Inside this function, we create 3 new variables, one to get the maxlength attribute of the input field we are targeting, the other to store the current character length in the text field, and the third to calculate the progress width according to the text field’s max length and current length.

const maxLength = inputField.getAttribute("maxlength");
const currentLength = inputField.value.length;
const progressWidth = (currentLength / maxLength) * 100;
Enter fullscreen mode Exit fullscreen mode

Next, we set the width of the progress bar to the value of the progressWidth variable. This adjusts the width percentage in line with the number of characters available in the text field.

progressBar.style.width = `${progressWidth}%`;
remChars.style.display = "none";
Enter fullscreen mode Exit fullscreen mode

After that, we set the background color of the progress bar according to the value of the progressWidth variable, setting it to green if the value is less than or equal to 60, orange if the value is greater than 60 but less than 85, and if the value is 85 or greater we set it to red and display how many characters are left to use.

if (progressWidth <= 60) {
    progressBar.style.backgroundColor = "rgb(19, 160, 19)";
  } else if (progressWidth > 60 && progressWidth < 85) {
    progressBar.style.backgroundColor = "rgb(236, 157, 8)";
  } else {
    progressBar.style.backgroundColor = "rgb(241, 9, 9)";
    remChars.innerHTML = `${maxLength - currentLength} characters left`;
    remChars.style.display = "block";
  }
}
Enter fullscreen mode Exit fullscreen mode

Now that we are done creating our character counter function, let's add an oninput event listener to listen for each character entered into the textarea field.

textarea.oninput = () => charCounter(textarea);
Enter fullscreen mode Exit fullscreen mode

After calling the function, each time a character is entered in or out of the textarea field, the progress bar width updates to show how much character space is left for use.

Conclusion

With this guide, you will be able to seamlessly include a character limit indicator in your next project, helping to improve the overall user communication experience in your application.

That's all for this article. You can check out the complete implementation of this project in the codepen below:

Also, if you're looking for a way to apply this to multiple textareas in your document, I have covered that in the comment section below. You can simply scroll down to check it out.

If there is a tutorial you would like me to cover, please don't hesitate to leave it in the comment sections. Till then, happy coding!😊

Top comments (23)

Collapse
 
marissab profile image
Marissa B

This was very clear, clever, and simple! It's one of those form quirks that we've all seen at some point but not all of us have implemented. I like that the text warning pops up towards the end to help with accessibility too.

Collapse
 
sarahokolo profile image
sahra πŸ’«

Thank youu :)

Collapse
 
thomasbnt profile image
Thomas Bnt β˜•

Your post is constructive and very clear, thanks ! πŸ™Œ

Collapse
 
sarahokolo profile image
sahra πŸ’«

Thank you πŸ™‚

Collapse
 
steeve profile image
Steeve

Thanks for the tutorial, I'll try to implement it into a small personnal project

Collapse
 
sarahokolo profile image
sahra πŸ’«

You're welcome :) Awesome

Collapse
 
keyurparalkar profile image
Keyur Paralkar

Nice article πŸš€

Collapse
 
sarahokolo profile image
sahra πŸ’«

Thank you :)

Collapse
 
cetinogut profile image
Cetin OGUT

very good and helpful, thanks.

Collapse
 
madempavankumar profile image
Madem Pavan Kumar

It's super cool

Collapse
 
sarahokolo profile image
sahra πŸ’«

Thank you :) :)

Collapse
 
nyangweso profile image
Rodgers Nyangweso

awesome

Collapse
 
sarahokolo profile image
sahra πŸ’«

Thankss :)

Collapse
 
gezd profile image
G

That was really well explained, thank you.
My site has a couple of text areas so i ended up adding a for loop to the javascript which detected all text areas and looped though them. Seems to work OK.
Let me know if you would like me to post the extended code.

Cheers

Collapse
 
sarahokolo profile image
sahra πŸ’«

That's a great workaround πŸ‘, and sure you can post the extended code

Collapse
 
gezd profile image
G • Edited

Sure thing. Now i will start by saying I am still very new to all this. But here goes.

Here is the HTML for the textareas:

//Text area 1
<label for="textArea1" class="requiredfield">This is the text area 1 text box</label>
<textarea id="textArea1" name="textArea1" spellcheck="true" rows="4" cols="50" maxlength="500"></textarea>
<div id="progress-textArea1">
    <div id="progress-bar-textArea1"></div>
    <p id="remaining-chars-textArea1"></p>
</div>

...

//Text area 2
<label for="textArea2" class="requiredfield">This is the text area 2 text box</label>
<textarea id="textArea2" name="textArea2" spellcheck="true" rows="4" cols="50" maxlength="500"></textarea>
<div id="progress-textArea2">
    <div id="progress-bar-textArea2"></div>
    <p id="remaining-chars-textArea2"></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Here is the updated CSS:

/*This is for the textArea character counter and progress bars*/
#progress-textArea1, #progress-textArea2 {
    width: 100%;
    height: 7px;
    box-shadow: inset 1px 1px 2px #ccc;
    border: 1px solid #bbb;
    border-radius: 15px;
  }

  #progress-bar-textArea1, #progress-bar-textArea2 {
    height: 100%;
  }

  #remaining-chars-textArea1, #remaining-chars-textArea2 {
    font-size: 11px;
    color: #b62020;
    margin-top: 3px;
    float: right;
    display: none;
  }
Enter fullscreen mode Exit fullscreen mode

And here is the updated Javascript:

/*
This section relates to the textArea character counter and progress bar
It loops through all textarea elements and processes each within the for loop.
This requires the progressBar IDs to be appended with the textArea field ID in the HTML and CSS
*/ 
let allTextArea = document.querySelectorAll("textarea");                
let numAllTextArea = allTextArea.length;                                

for (let i=0; i<=numAllTextArea; i++) {
    let fieldToProcess = allTextArea[i].id;                             
    let progressBarId = "progress-bar-"+fieldToProcess;                 
    let remCharsId = "remaining-chars-"+fieldToProcess;                 

    let textArea = document.getElementById(fieldToProcess);             
    let progressBar = document.getElementById(progressBarId);           
    let remChars = document.getElementById(remCharsId);                 

    function charCounter(inputField) {
        let maxLength = inputField.getAttribute("maxlength");           
        let currentLength = inputField.value.length;                      
        let progressWidth = (currentLength / maxLength) * 100;            

        progressBar.style.width = `${progressWidth}%`;                    
        remChars.style.display = "none";

        if (progressWidth <= 60) {
            progressBar.style.backgroundColor = "#00594c";
        } else if (progressWidth > 60 && progressWidth < 85) {
            progressBar.style.backgroundColor = "#ffd602";
        } else {
            progressBar.style.backgroundColor = "#b8232f";
        }
        remChars.innerHTML = `${maxLength - currentLength} characters left`;
        remChars.style.display = "block";
        }

        textArea.oninput = () => charCounter(textArea);
    }
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
sarahokolo profile image
sahra πŸ’« • Edited

That's quite nice, but I do find some little issues that might arise with this approach. The first issue being that the warning text doesn't popup at the end, instead it's visible from start to finish, which doesn't look right. Also, I added two new texareas, but they didn't seem to be functional as the first two. Overall, having a function Inside a for loop like that isn't a very neat approach, makes the code unscalable and the function hard to maintain.

A cleaner and easier approach to achieve this for multiple textareas in the document is to separate the function from the for loop.

Here is my updated counter function:

const textareas = document.querySelectorAll(".txt");
const progressBars = document.querySelectorAll(".progress-bar");
const remCharsElems = document.querySelectorAll(".remaining-chars");

function charCounter(inputField, progress, warningTxt) {
  const maxLength = inputField.getAttribute("maxlength");
  const currentLength = inputField.value.length;

  const progressWidth = (currentLength / maxLength) * 100;
  progress.style.width = `${progressWidth}%`;
  warningTxt.style.display = "none";

  if (progressWidth <= 60) {
    progress.style.backgroundColor = "rgb(19, 160, 19)";
  } else if (progressWidth > 60 && progressWidth < 85) {
    progress.style.backgroundColor = "rgb(236, 157, 8)";
  } else {
    progress.style.backgroundColor = "rgb(241, 9, 9)";
    warningTxt.innerHTML = `${maxLength - currentLength} characters left`;
    warningTxt.style.display = "block";
  }
}
Enter fullscreen mode Exit fullscreen mode

This way the function logic has been separated and can be used anywhere.

Here is the forEach loop to get all the texareas in the document and apply the counter function to them.

textareas.forEach((textarea, i) => {
  textarea.oninput = () => charCounter(textarea, progressBars[i], remCharsElems[i]);
})
Enter fullscreen mode Exit fullscreen mode

Now, you can add as many texareas as you want, without needing to modify the JavaScript again.
You can check it out in the codepen below, where I added two new textareas with different maxlengths:

Collapse
 
koteisaev profile image
Kote Isaev - #StandWithUkraine

Interesting that progress tag still not so easy to use for this use case that fits into purpose of element only because getting it styled properly is not so easy as it should.

Collapse
 
sarahokolo profile image
sahra πŸ’«

I initially started with the progress tag, because I wanted to stick to semantics, but unfortunately it's styling capabilities and browser inconsistencies we're just too much of a hassle. They really should make the progress element more style flexible.

Collapse
 
koteisaev profile image
Kote Isaev - #StandWithUkraine

It seems that simplest way to achieve that would be adopting that webkit kind of implementation as default and wait till it will get enough distribution to be considered "widespread enough". Mozilla variant is more limited, sadly.

Collapse
 
moopet profile image
Ben Sinclair

Nice, nice.

I would probably caution people not to do this unless there's a good reason though. It can be very frustrating to find a form which asks you to enter, say, the steps that caused the problem you've had, and to not have enough room to type it all.

In most situations, your application should accept such a large amount of text that displaying a message is irrelevant.

Collapse
 
sarahokolo profile image
sahra πŸ’«

Yeah, it most definitely isn't for all use cases. But It can be useful for a social media post, or when the information requested isn't allowed to be too lengthy.

Collapse
 
andreagelmini profile image
Andrea Gelmini

Hello, I liked your code and recently I have been dedicating myself to studying Stimulus.js. Therefore, I decided to create a version of your code for Stimulus. For convenience, I used Tailwind CSS

I hope it can be useful to someone.