Skip to content

Conversation

amyleadem
Copy link
Contributor

@amyleadem amyleadem commented Aug 8, 2022

Summary

Updated the validation component so that users of assistive technologies can receive status updates about the completion of each validation requirement. This was done by adding a script that generates appropriate ARIA attributes.

Details

Added a script that generates an aria-label for each checklist item. This allows assistive technologies users to navigate to each checklist item and receive the current status of each validation requirement.

Added a script that generates a new span to house the summary of the validation status updates. This span has aria-live and aria-atomic attributes so that users of assistive technologies will be notified of status changes.

Removed the aria-checked attribute from list items in the validation component. This attribute is no longer needed now that a text element informs the user if the requirement is complete or incomplete.

Added data-validation-complete and data-validation-incomplete attributes so that users can customize copy for status complete and status incomplete messages.

Related issue

Closes: #4905

Related PRs: This PR incorporates the changes originally merged in #4719 that were later reverted in #4906. This PR includes the original update from #4719 and resolves the errors that caused the reversion.

Preview link

Preview link: Validation component

Problem statement

Including the aria-checked attribute generates errors

Adding the aria-checked attribute to a <li> item results in the following a11y error:

Errors in http://localhost:4000/components/validation/:

 • Elements must only use allowed ARIA attributes
   (https://dequeuniversity.com/rules/axe/3.5/aria-allowed-attr?application=axeAPI)

   (#validate-code > li:nth-child(1))

   <li class="usa-checklist__item" data-validator="uppercase"
   aria-checked="false"> Use at least one u...</li>

 • Elements must only use allowed ARIA attributes
   (https://dequeuniversity.com/rules/axe/3.5/aria-allowed-attr?application=axeAPI)

   (#validate-code > li:nth-child(2))

   <li class="usa-checklist__item" data-validator="numerical"
   aria-checked="false"> Use at least one n...</li>

These errors reveal that items with the aria-checked attribute also need an appropriate role. Reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked#associated_roles

However, adding role="checkbox" to the <li> item also returns an error:

Detected the following accessibility violations!
       
       1. aria-allowed-role (ARIA role should be appropriate for the element)
       
          For more info, visit https://dequeuniversity.com/rules/axe/4.3/aria-allowed-role?application=axeAPI.
       
          Check these nodes:
       
          - html: <li class="usa-checklist__item" data-validator="uppercase" role="checkbox" aria-checked="true">Use at least one uppercase character</li>
            summary: Fix any of the following:
                       ARIA role checkbox is not allowed for given element

VoiceOver produces a confusing readout

Additionally, VoiceOver generates undesirable and inconsistent readouts. Items can be read twice or only partially.

Solution

aria-checked

The data-checklist-label element now informs the keyboard user if the validation requirements are complete or incomplete. There is no longer a need to use an attribute like aria-checked to communicate complete or incomplete to the user.

Confusing readout

Changing the following items generated a more consistent readout in VoiceOver:

  • Generated an aria-label for each checklist item that includes the original text content plus the item's current status
  • Generated a new sr-only span with aria-live and aria-atomic attributes that houses the summary of all checklist items plus their individual statuses.

Tasks completed in this PR:

  1. Integrated changes created in cm-validation-a11y branch 0684b17
  2. Removed the aria-checked attribute from the list item f077275
  3. Added tabindex="0" to make the items in the validation checklist items easier to navigate via tab 29c2b61
  4. Created a new sr-only span element with aria-live and aria-atomic attributes that houses a status summary 07ad7de
  5. Added optional data-validation-complete and data-validation-incomplete attributes eeb2e18

Testing and review

Using the screen readers you have available,

  1. Confirm that validation status is discoverable via keyboard navigation .
  2. Confirm that the validation status is read out in a way that makes sense.
  3. Confirm that the validation component passes a11y tests.
  4. Add the following data attributes with custom values to .usa-input and confirm that the status message in data-checklist-label updates accordingly:
    • data-validation-complete
    • data-validation-incomplete

Tested on:

  • VoiceOver on Firefox, Safari, Edge for MacOs
  • VoiceOver Gestures on iOS

Before opening this PR, make sure you’ve done whichever of these applies to you:

  • Run git pull origin [base branch] to pull in the most recent updates from your base and check for merge conflicts. (Often, the base branch is develop).
  • Run npm test and confirm that all tests pass.

@amyleadem amyleadem changed the base branch from develop to cm-validation-a11y August 11, 2022 16:28
@amyleadem amyleadem changed the base branch from cm-validation-a11y to develop August 11, 2022 16:28
@amyleadem amyleadem marked this pull request as ready for review August 11, 2022 21:31
@amyleadem amyleadem requested a review from mejiaj August 11, 2022 21:31
@amyleadem
Copy link
Contributor Author

@mejiaj I wasn't sure how best to work with the previously merged PR, so I simply brought in the changes from that PR into this branch. Please let me know if there is a cleaner path.

Copy link
Contributor

@mejiaj mejiaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on our testing, let's try using an aria label on the list items to improve how it gets announced via screenreader.

@amyleadem
Copy link
Contributor Author

@mejiaj I made some updates to improve the readout in VoiceOver. Surprisingly, an <i> element generated a more reliable readout than the <span> (at least in VO). Will you check this on your screen readers and let me know your thoughts?

@amyleadem amyleadem requested a review from mejiaj September 22, 2022 00:11
@mejiaj
Copy link
Contributor

mejiaj commented Sep 22, 2022

@amyleadem it does read better in voiceover! The only thing I've noticed is that the list item doesn't read out the updated status when I tab to it. Instead, it will just read the requirements without the current status.

The only way I can get the status to be read is to focus out and back in to the input element.

@amyleadem
Copy link
Contributor Author

@mejiaj Switched it up a bit and generated an aria-label for the checklist items instead of generating a new text element. Will you let me know what you think?

Copy link
Contributor

@mejiaj mejiaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well, on VoiceOver I was able to verify functionality has improved:

  • Elements read correctly
  • Validation requirements update and read properly

Component also still works when inserting dynamically.

I've added some suggestions for improving code and some questions about aria attributes on the input element.

@amyleadem
Copy link
Contributor Author

@mejiaj
Thanks for the helpful review. I wanted to show you one more possible approach that has gotten the cleanest readout so far and would not interfere with with the aria-label on the input. This option generates a span that is a peer to the input and checklist elements, has the aria-live and aria-atomic attributes, and gathers the status updates for all checklist items into a single element for readout.

The current proposed solution also generates an aria-label for each checklist item that includes the item's current status, so users can still get check the status of each individual element.

The only concern I have is that creating a fully new text element might be too clumsy and cause some unexpected problems. It would be great to hear your thoughts.

Additionally, I created an enhanceValidation() function, but I am not sure I fully understand how best to do this. Will you take a look and let me know if this is doing what you hoped?

@amyleadem amyleadem requested a review from mejiaj September 27, 2022 16:38
Copy link
Contributor

@mejiaj mejiaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amyleadem it does read better. Added some thoughts below.

Overall, if we want the new status element we would have to link it to the input (which seems to be performing the same function as the list with aria-live="polite").

I do see the potential of this improving the experience, especially after seeing GovUKs character count recommendations in #4714. If we want to go that route we'd probably need to:

  • Link the input to this new status via a unique ID and aria-describedby
  • Set a delay on the status so it can finish reading user input and then give status

@amyleadem
Copy link
Contributor Author

@mejiaj
Thanks a ton for the helpful review. I believe I have addressed all the comments above. Please let me know if you see anything else!

Tasks completed:

  • Moved enhanceValidation to init in a57aff1
  • Added aria-describedby to input in a57aff1
  • Split out the functions in 853fb7d
  • Added a delay for the screen reader readout in 9162036
  • Updated handleChange() to be more explicit in aa38ecb

@amyleadem amyleadem requested a review from mejiaj October 6, 2022 18:55
Copy link
Contributor

@mejiaj mejiaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, the experience has improved for users on screen readers with the delayed announcement.

Added some suggestions we could use to improve code readability.

Comment on lines 35 to 46
let statusComplete = "status complete";
let statusIncomplete = "status incomplete";
let checkboxContent = `${validatorCheckbox.textContent} `;

if (el.hasAttribute("data-validation-complete")) {
statusComplete = el.getAttribute("data-validation-complete");
}

if (el.hasAttribute("data-validation-incomplete")) {
statusIncomplete = el.getAttribute("data-validation-incomplete");
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could simplify this by having these labels as a backup in case the dataset comes back null or undefined.

Suggested change
let statusComplete = "status complete";
let statusIncomplete = "status incomplete";
let checkboxContent = `${validatorCheckbox.textContent} `;
if (el.hasAttribute("data-validation-complete")) {
statusComplete = el.getAttribute("data-validation-complete");
}
if (el.hasAttribute("data-validation-incomplete")) {
statusIncomplete = el.getAttribute("data-validation-incomplete");
}
const statusComplete = el.dataset.validationComplete || "status complete";
const statusIncomplete = el.dataset.validationIncomplete || "status incomplete";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean! Updated in aea87ce

Comment on lines 60 to 62
((debounce(() => {
statusSummaryContainer.textContent = statusSummary;
}, 1000)))();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional because we have the comment, but we can increase readability by extracting it to it's own updateSRSummary() and just calling it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that it could make it more consistent with the new character count setup. Updated in bfbfd52

(If I misunderstood your request, feel free to fix while I am out!)

@amyleadem amyleadem requested a review from mejiaj October 7, 2022 20:35
Copy link
Contributor

@mejiaj mejiaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well, tested for regressions and VoiceOver. Has a debounce function that was introduced in PR #4976.

Copy link
Contributor

@thisisdano thisisdano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice discussion and nice work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

USWDS - Bug: Fix invalid aria role in validator list items
3 participants