Slide instructions

SPACEBAR to move forward through slides.

SHIFT & SPACEBAR to move backwards through slides.

LEFT ARROW & RIGHT ARROW to move through sections.

ESC to see overview and ESC again to exit.

F to enter presentation mode and ESC to exit.

Creating an accessible character counter

AccessU 2024

Acknowledgement of Country

I’d like to acknowledge the Traditional Owners of the lands on which I am running this session today.

I’d like to pay my respects to Elders past and present, and extend to all First Nations people who are here today or may watch the recording later.

In my case, I am on the lands of the Cammeraygal people of the Eora Nation.

Some housekeeping

My name is Russ Weakley. I am the Head of Inclusive Training and Intopia.

My presentation is available online, if you want to follow along.

Short link: https://bit.ly/4apIUCK

Use the SPACEBAR to move through each slide.

Feel free to ask questions at any time - in chat or in person!

We’ll also be marking up an example character counter. You can play along if you want!

We will be using CodePen for the coding activity. You don't need an account to take part.

What is a character counter?

Let's start with the various aspects of a character counter component.

As you can see, character counters help people know how much text they can enter when there is a limited number of characters.

Ideally, these components provide people with live feedback to inform them about the following information:

1. How many characters they have typed or remain before reaching the limit.

2. When they reach or exceed the character limit.

The USWDS character counter is a great example.

How could we make an accessible character counter component?

Starting with people and their needs

When creating any new component, it is important to understand how it could impact different types of people.

I like to group people based on similar needs. For example:

  1. People with varied learning or cognition.
  2. People with reduced colour vision.
  3. People with reduced vision.
  4. People with reduced movement.
  5. People with no vision.

The order?

I prefer to start with people with varied learning or cognition.

If the component does not work for these people, it has fundamental content or UX issues.

These issues should be addressed before conducting any other testing.

I then focus on the people with reduced colour vision and reduced vision for all visual aspects of the component.

Then, focus on people with reduced movement and no vision for the more technical aspects of the component.

So, let’s look at these different groups of people and their needs when interacting with a character counter.

People with varied learning or cognition

In reality, these checkpoints are relevant for all users!

1. The purpose of the component is clear.

2. All labels, instructions and error messages are meaningful.

3. All labels, instructions and error messages are persistent.

4. If users make a mistake, they can recover quickly.

5. Users are provided with feedback on the number of characters remaining.

6. Users are provided with feedback when the character number has been exceeded.

Sighted users

1. All labels, instructions and error messages are visible.

2. All labels, instructions and error messages are in close proximity to the relevant form control.

3. Error and warning messages are distinguishable from other messages.

People with reduced colour vision

1. All relevant aspects of the component have sufficient colour contrast.

2. Any information conveyed by colour is accompanied by a visible alternative that does not depend on colour for meaning.

People with reduced vision

1. The component is operable/understandable when text is scaled.

2. The component is operable/understandable when the overall layout is scaled.

3. The component is operable/understandable when aspects of the component are magnified.

4. The component is operable/understandable when displayed with different text and paragraph spacing.

5. The component is operable/understandable when displayed in low contrast.

6. The component is operable/understandable when displayed in different viewport sizes.

People with reduced movement

1. Focus is managed into, within and out of the component.

2. Focus order follows a meaningful sequence.

3. All actions can be executed using keystrokes only.

4. All actions can be executed using voice controls.

5. All keystrokes are intuitive for keyboard-only users.

6. All visible focus states are clearly defined.

In this case, the component is very simple, so many of these points should be easy to achieve.

People with no vision

1. The form control has an accessible name.

2. The form control has a meaningful role.

3. All relevant labels, instructions and error messages are programmatically associated with the form control.

4. Users are provided with feedback on the number of characters remaining - at appropriate times.

5. Users are provided with feedback when the character number has been exceeded - at appropriate times.

What do we mean by ‘appropriate times’? Stay tuned!

Let’s look at how we could mark up our component.

Marking up the basic character counter

For this example, we will not cover detailed JavaScript solutions; we’ll focus on the markup.

Play along:

Viewing the accessibility tree

At times during this activity, I will be showing you the accessibility tree using the Chrome browser.

This accessibility tree consists of information about specific HTML elements, including their:

  • Name (e.g. ‘Submit’, ‘Full name’)
  • Role (e.g. button, link, textbox)
  • State (e.g. checked, expanded, disabled)
  • Value (e.g. input from the user)

Accessibility APIs communicate this information from the accessibility tree to assistive technologies like screen readers.

Each browser supports different Accessibility APIs, which means they each produce their own unique accessibility tree.

Let’s have a quick look at the accessibility tree in Chome.

Let’s begin the activity

At each step, I will copy and paste the code example into chat.

Step 1:

Add a <label>:

<label class="label">
  Add a comment
</label>
Step 2:

Add the instructions:

<label class="label">
  Add a comment
</label>
<span class="help-text">
  Enter up to 50 characters
</span>
Step 3:

Add the <textarea>:

<label class="label">
  Add a comment
</label>
<span class="help-text">
  Enter up to 50 characters
</span>
<textarea class="input">
</textarea>
Step 4:

Programmatically associated the label with the <textarea> using matching for and id values:

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1">
</textarea>

The <textarea> should now have an accessible name.

Step 5:

Programmatically associated the instructions with the <textarea> using matching aria-describedby and id values:

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1">
</textarea>

The <textarea> should now have an accessible description.

Sidenote: the maxlength attribute

Some people like to use the maxlength attribute here, to limit the maximum number of characters that users can type into the field.

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1"
  maxlength="50">
</textarea>

I prefer not to use this method as it will suddenly stop adding chracters when the maximum character length has been reached.

It will also stop announcing character input to screen readers, which may be confusing.

Instead, we will let users keep typing, but inform them that they have exceeded the maximum number of characters.

Step 6:

Add an on-screen message character count message:

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1">
</textarea>
<span class="character-text">
  27 characters left
</span>

This message is only for sighted users and does not need to be programmatically associated with the form control.

This on-screen message would be dynamically updated using JavaScript as the user types each new character.

The on-screen message would also change when the character count limit has been exceeded.

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1">
</textarea>
<span class="character-text">
  5 characters over the limit
</span>

We have a problem!

The problem is that changing this message with each keystroke would be too verbose for screen reader users.

This dynamic information would be announced over the top of user interaction announcements.

These people may not be able to hear what characters they are typing.

So, we need to hide this information from screen readers.

Step 7:

We can ensure this information is not presented to screen readers using aria-hidden="true".

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1">
</textarea>
<span class="character-text" aria-hidden="true">
  27 characters left
</span>

This element will now be unavailable in the accessibility tree.

Step 8:

We could then add a screen reader-only message that will be less verbose.

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1">
</textarea>
<span class="character-text" aria-hidden="true">
  27 characters left
</span>
<span>
  27 characters left
</span>
Step 9:

This information can be hidden off-screen so it is only available to screen readers.

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1">
</textarea>
<span class="character-text" aria-hidden="true">
  27 characters left
</span>
<span class="hidden">
  27 characters left
</span>

But how do we make this information ‘less verbose’?

We can use JavaScript Debounce to determine how often the screen reader-only message updates.

Debouncing is a programming technique that helps to improve the performance of web applications by limiting the frequency of function calls.

DEV.TO

In this case, we can use JavaScript to wait for a pause in user typing before updating the screen reader-only message.

Step 10:

We can also set this message with aria-live="polite" so that the information is announced at the next graceful opportunity.

<label class="label" for="b1">
  Add a comment
</label>
<span class="help-text" id="a1">
  Enter up to 50 characters
</span>
<textarea class="input" id="b1" aria-describedby="a1">
</textarea>
<span class="character-text" aria-hidden="true">
  27 characters left
</span>
<span class="hidden" aria-live="polite">
  27 characters left
</span>

For these users, the character count information would only be announced when there is a pause in typing.

Let’s interact with the USWDS character counter using a screen reader.

Reviewing our checklist?

Let’s recap the points from before.

Ideally, each point should pass in order for the character counter component to be considered accessible.

People with varied learning or cognition

  • The purpose of the component is clear.
  • All labels, instructions and error messages are meaningful.
  • All labels, instructions and error messages are persistent.
  • If users make a mistake, they can recover quickly.
  • Users are provided with feedback on the number of characters remaining.
  • Users are provided with feedback when the character number has been exceeded.

Sighted users:

  • All labels, instructions and error messages are visible.
  • All labels, instructions and error messages are in close proximity to the relevant form control.
  • Error and warning messages are distinguishable from other messages.

People with reduced colour vision

  • All relevant aspects of the component have sufficient colour contrast.
  • Any information conveyed by colour is accompanied by a visible alternative (text, image, etc.) that does not depend on colour for meaning.

People with reduced vision

The component is operable/understandable:

  • When text is scaled to 200%.
  • When the overall layout is scaled to 400%.
  • When aspects of the component are magnified.
  • When displayed in low contrast.
  • When displayed in different viewport sizes.
  • When displayed with different text and paragraph spacing.

People with reduced movement

  • Focus managed into, within and out of the component.
  • Focus order follows a meaningful sequence.
  • All actions can be executed using keystrokes only.
  • All actions can be executed using voice controls.
  • All keystrokes are intuitive for keyboard-only users.
  • All visible focus states are clearly defined.

People with no vision

  • The form control has an accessible name.
  • The form control has a meaningful role.
  • All relevant labels, instructions and error messages are programmatically associated with the form control.
  • Users are provided with feedback on the number of characters remaining - at appropriate times.
  • Users are provided with feedback when the character number has been exceeded - at appropriate times.

Questions or discussion?