8

I'm looking to enhance my WordPress theme's "Meta Description" and "title" tag input fields and I'd like to add a text snippet that evaluates the text input field after each keypress and updates the fields "target character count" just like Twitter's does.

For example, on the "Meta Description" field, the target character count is 160. So, if the field is blank, the number would be 160. As the user types, the count is decreased with each character added to the input field until it reaches zero.

If the count is higher than the target, the numbers are written in red with a minus sign in front (again, just like twitter).

Is there an existing jQuery script to do this?

<label class="screen-reader-text" for="excerpt">
    Post Excerpt (Meta Description) <span class="counter">150</span> characters*         
</label>

<textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt"></textarea>
RegEdit
  • 2,134
  • 10
  • 37
  • 63
  • 1
    Googling for `Remaining Characters JQuery` says [Yes](http://plugins.jquery.com/plugin-tags/character-counter). – GolezTrol Oct 28 '11 at 20:20
  • 2
    possible duplicate of [Countdown available spaces in a textarea with jquery or other?](http://stackoverflow.com/questions/1250748/countdown-available-spaces-in-a-textarea-with-jquery-or-other) Note that plenty of solutions use `keyup` for this, which is extremely annoying. You should use the `input` event where supported. Google for *"jQuery HTML5 oninput"*. – Andy E Oct 28 '11 at 20:21

6 Answers6

15

Not that I know of, but here's something to get you started: http://jsfiddle.net/yzLbh/

Edit: Andy E is right - I should have (and now have) added support using the input event, which works if you hold a key down, paste, drag, etc. on browsers that support it. http://jsfiddle.net/yzLbh/5/

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • +1 since it works exactly like Twitter. However, I don't think I can add the maxlength attribute to the input field, since that's controlled by WordPress core. Also, I don't want to cut the text off at maxlength, I just want to feedback to the user when they have exceeded it. – RegEdit Oct 28 '11 at 20:29
  • @RegEdit: Just change the name of the attribute, then, and it won't be enforced strictly. – Ry- Oct 28 '11 at 22:11
  • @RegEdit: I've also edited my post to include an `input`-capable version, which is more like Twitter. – Ry- Oct 28 '11 at 22:15
  • What is this black magic? `'oninput' in document.createElement('input');`? On closer inspection I think you're creating an input, checking if it supports `onInput` event and then checking binding to `onInput` or `keyUp` depending on the result of the support. – The Muffin Man Sep 05 '13 at 03:47
  • @Nick: Yep, I would probably just bind to both nowadays. Or at least mention something. Sorry D: – Ry- Sep 05 '13 at 03:55
  • 3
    @minitech Looks pretty elegant to me. I like it, I actually just put it on a clients website. I found 1 bug though `el.css('color', null);` should be `el.css('color', '');`. Says so in the docs too :). Also for my case I changed the selector to `:input` so that it matches all inputs including textareas. – The Muffin Man Sep 05 '13 at 03:58
  • doesn't support the enter key. twitter accepts enter key. – Tito Jul 07 '15 at 03:34
  • @TitoCheriachan: Okay, so use a ` – Ry- Jul 07 '15 at 05:24
7

It's nothing too complicated:

JS:

maxCharacters = 160;

$('#count').text(maxCharacters);

$('textarea').bind('keyup keydown', function() {
    var count = $('#count');
    var characters = $(this).val().length;

    if (characters > maxCharacters) {
        count.addClass('over');
    } else {
        count.removeClass('over');
    }

    count.text(maxCharacters - characters);
});

HTML:

<textarea></textarea>

<p>
    <strong>You have <em id="count"></em> characters remaining</strong>
</p>

CSS:

.over {
    color: red;
}

Demo: http://jsfiddle.net/HgfPU/10/

You basically handle every event on the textarea and check whether the length is greater/lesser than a threshold.

Blender
  • 289,723
  • 53
  • 439
  • 496
0

Bind a function on change of the input, check the length of the text, perform the subtraction, and update a div with it.

HTML

<input type='text' id='from_box' />
<div id='to_box'><span id='remaining'>160</span> characters remaining</div>

jQuery

$("#from_box").bind("keyup", function(){
    var max_characters = 160;
    var total_used = $("#from_box").val();
    var remaining = max_characters - total_used;
    $("#remaining").text(remaining);
});
Whetstone
  • 1,199
  • 8
  • 8
  • 1
    `change` doesn't fire until the element is blurred. `"input propertychange keyup"` would give you the best experience. – Andy E Oct 28 '11 at 20:25
  • @AndyE I'm sorry, I must be missing something. This code works fine (see minitech's similar example jsfiddle below), but if I'm doing something improperly I'd love to learn. – Whetstone Oct 28 '11 at 20:29
  • @Whetstone: What you are doing inproperly still is using global variables (they are not necessary). Please learn to use `var` before variable declarations - it will make your code smarter, cleaner and more reliable. – Tadeck Oct 28 '11 at 20:35
  • @Tadeck it was a quick piece of code for demo purposes, however thank you for the advice :). Andy was mentioning something else and I'm looking to know what it was. – Whetstone Oct 28 '11 at 20:50
  • @Whetstone: I believe you know why `var` is a must in this case, I am more worried about the people that may take this code literally and place it somewhere on the web ;) They may not be aware of the `var`-less JS code consequences :) – Tadeck Oct 28 '11 at 20:54
  • @Tadeck I'm not trying to pick on such a small issue, and agree that the above code is _improper_, but not inherently wrong. Assuming these variables are unique, it is not a must to declare `var` beforehand. I will agree that it is improper though, and have changed accordingly. So that I can learn, can you explain why you view it as a must? – Whetstone Oct 28 '11 at 20:57
  • @whetstone key events just aren't sufficient for detecting input. See http://whattheheadsaid.com/2010/09/effectively-detecting-user-input-in-javascript. – Andy E Oct 28 '11 at 22:22
  • @Whetstone: This is a must because of the fact it violates the encapsulation & modularity rules of the code - due to some design decisions (some say _bad_ decisions) JavaScript uses global variables as default, and variables preceded by `var` keyword as local ones. In different languages its usually the opposite, but this should not trip you up - in JavaScript when you define locally used variables without `var`, you are unnecessarily defining global ones and they may interfere with some different code, probably even unrelated to yours. Hope it shows you the reason. – Tadeck Oct 28 '11 at 23:36
0

take a look at this list of plugins:

http://plugins.jquery.com/plugin-tags/character-counter

swatkins
  • 13,530
  • 4
  • 46
  • 78
0

Check: http://jsfiddle.net/2FLjt/

$('#checkval').keyup( function() {

    var value = $(this).val();
    // get MAX chars from textarea
    var maxlength = $(this).data("maxlength");

    var compare = maxlength - value.length;
    // decide if chars is under/over
    if (compare >= 0) {
        $("#inputcounter").removeClass('error').html(compare + "characters left");
    } else if (compare < 0) {
        $("#inputcounter").addClass('error').html(compare + "characters left");
    }

});
Marco Johannesen
  • 13,084
  • 6
  • 31
  • 36
  • 1
    Why are you checking whether `compare >= 0` and then `compare < 0`? If this isn't true: `compare >= 0)` then this has to be: `compare < 0`. I'd get rid of `else if (...)` and just use `else`. – Blender Oct 28 '11 at 20:32
  • It don't work if the user paste some text by right-clicking and selecting paste. – Metalcoder Sep 09 '15 at 18:55
0

You can do it like that (see this jsfiddle for a proof):

  • HTML:

    <input type="text" class="twitter-like" value="" />
    <div>Remaining characters: <span class="twitter-counter" data-default-value="160"></span></div>
    
  • JavaScript:

    var counter = jQuery('span.twitter-counter[data-default-value]');
    counter.html(counter.data('default-value'));
    jQuery('input.twitter-like').bind('keyup',function(){
        counter.html(counter.data('default-value') - jQuery(this).val().length);
    });
    
Tadeck
  • 132,510
  • 28
  • 152
  • 198