So I have implemented a character counter for a textarea element. When there is 1 character left, JAWS should read "1 character remaining of 150 characters" but reads "1 characters remaining of 150 characters". Then when I change the character count by entering any key or backspace, it reads "x character remaining of 150 characters". Anyone know why JAWS is doing this? Here is the link to the demo: http://codepen.io/obliviga/pen/gLyKYj?editors=1010
HTML:
<div class="field">
<label class="input-label" for="styleguide-input-textarea">Comments</label>
<textarea class="input-textarea" id="styleguide-input-textarea" aria-describedby="chars-remaining" name="" aria-multiline="true"></textarea>
<div id="chars-remaining">
<span id="live-region-text" aria-live="polite">
<span class="count">150</span> character<span id="styleguide-input-textarea-plural">s</span> remaining
</span>
of 150 characters
</div>
</div>
Javascript:
function charsRemaining() {
// the total number of characters allowed:
var totalChars = 150;
// the number of characters that
// triggers the polite announcement:
var politeFlag = 80;
// the number of characters that
// triggers the assertive announcement:
var assertiveFlag = 130;
var $message = $('#styleguide-input-textarea');
$message.attr('maxlength', totalChars);
$message.on('keyup', function (e) {
// maxlength polyfill:
// Get the value
var text = $(this).val();
// Get the maxlength
var limit = $(this).attr('maxlength') || totalChars;
// Check if the length exceeds what is permitted
if(text.length > limit){
// Truncate the text if necessary
$(this).val(text.substr(0, limit));
}
// chars remaining
var realLength = $message.val().length;
var remaining = totalChars - realLength;
updateRemaining(remaining);
// 70-60 atomic true
// 60 set it to false
// 20 atomic true
if (realLength >= politeFlag && realLength < assertiveFlag) {
// polite announcement
$('#live-region-text').attr('aria-live', 'polite');
if (realLength >= 90) {
$('#live-region-text').attr('aria-atomic', 'false');
} else {
$('#live-region-text').attr('aria-atomic', 'true');
}
} else if (realLength >= assertiveFlag) {
// assertive announcement
$('#live-region-text').attr({
'aria-live': 'assertive',
'aria-atomic': 'true'
});
} else { // clean up (remove the aria-live and aria-atomic attributes)
$('#live-region-text')
.removeAttr('aria-live')
.removeAttr('aria-atomic');
}
if (remaining === 1) {
$('#styleguide-input-textarea-plural').hide();
} else {
$('#styleguide-input-textarea-plural').show();
}
});
}
function updateRemaining(charsLeft) {
$('#chars-remaining .count').html(charsLeft);
}
charsRemaining();