DEV Community

Gerald Allay
Gerald Allay

Posted on • Updated on

Alpine.js Build a Remaining Character Count Component

First things first lets include Alpine to our project by including it from script tag.

<html>
  <head>
<script defer src="https://unpkg.com/alpinejs@3.2.3/dist/cdn.min.js"></script>
</head>
<body>
...
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

The script tag fetches alpinejs (in this case Version 3.2.3) from CDN. The defer attribute is important here because it tells the browser not to wait for the script, instead browser continue to process the HTML and build the DOM.

Next lets layout some basic markup for our character counter. We have a parent div, a textarea input with maxlength attribute set to 120 which will help us to enforce the limit (shout out to @marzelin for pointing that out in the comments) and a p tag that we will use to display remaining characters while user is typing.

...
<div>
    <textarea maxlength="120"></textarea>
    <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

To continue with Alpine we need to ensure Alpine can initialize a new component. We do this by using x-data directive. Inside x-data you can declare object of data that Alpine will track. Lets just leave it empty for now.

<div x-data="">
    <textarea maxlength="120"></textarea>
    <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Now we can add property that will hold contents of textarea to x-data directive.

<div x-data="{content: ''}">
    <textarea maxlength="120"></textarea>
    <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

We need to hook the content property to textarea. We can achieve this by using x-model directive, which allows you to bind the value of an input element to Alpine data. x-model is two-way bound, meaning it both "sets" and "gets". In addition to changing data, if the data itself changes, the element will reflect the change.
I will also add x-ref directive which we'll letter use to get reference of textarea element.

<div x-data="{content: ''}">
    <textarea x-model="content" x-ref="message"></textarea>
    <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

All that is left now is to display the number of remaining characters, but first we need to add new property on our component to hold the limit which is the value of maxlength. To do that we can use $refs property which is used to retrieve DOM elements marked with x-ref. Think of x-ref and $refs as a replacement for APIs like getElementById and querySelector.

<div x-data="{content: '', limit: $refs.message.maxLength}">
    <textarea maxlength="120" x-ref="message" x-model="content"></textarea>
    <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Now we can count how many characters the content has, and substract from our limit to get the remaining characters. Alpine has x-text directive that set text of an element to the result of given expression.

<div x-data="{content: '', limit: $refs.message.maxLength}">
    <textarea maxlength="120" x-ref="message" x-model="content"></textarea>
    <p x-text="limit - content.length"></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Lets improve it a little bit with more information to our user

<div x-data="{content: '', limit: $refs.message.maxLength}">
    <textarea maxlength="120" x-ref="message" x-model="content"></textarea>
    <p> You have 
       <span x-text="limit - content.length"></span>
      characters remaining
</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
marzelin profile image
Marc Ziel

It would be nice if you first show how to add alpine.js to the document:

<script src="//unpkg.com/alpinejs" defer></script>
Enter fullscreen mode Exit fullscreen mode

How would you enforce this limit?

Collapse
 
allaygerald profile image
Gerald Allay

Thanks for pointing that out.
One way to inforce the limit is by using HTML's maxLength attribute. I will update my post to cover that.