Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor character count to inject new element #2577

Merged
merged 12 commits into from
Apr 12, 2022

Conversation

querkmachine
Copy link
Member

@querkmachine querkmachine commented Mar 21, 2022

Modifies the character count JavaScript to compose and inject new elements that are live-updated, instead of overwriting the content of the initial HTML hint.

There are now three elements responsible for character count announcements:

  • A static element that describes the character limit (e.g. "You can use up to 200 characters").
    • This is present in HTML, and serves as the fallback if JavaScript is unavailable.
    • It is visible if JavaScript is unavailable, and visually hidden if it is.
    • It is announced by screen readers when the user first focuses on the textarea, before they type.
    • Screen readers will always read this out, even if a counter utilises a threshold.
  • An injected, live-updating element showing the characters remaining (e.g. "You have 200 characters remaining").
    • This is visible, updates immediately in response to user input, and uses aria-hidden to hide itself from screen readers.
    • If the counter has a threshold, this is invisible until after the user has passed the threshold.
  • An injected, debounced element showing the characters remaining (e.g. "You have 200 characters remaining").
    • This is invisible, only updates after one second of inactivity, and is announced by screen readers following input using aria-live="polite".
    • If the counter has a threshold, this is only announced once the user has passed the threshold.

Only the first element must be present in the initial HTML. The other two are injected when JavaScript runs.

Upgrading

Users of the govuk-frontend Nunjucks macros do not have to make any changes.

Users of static HTML can remove the hardcoded aria-live="polite" attribute from .govuk-character-count__message. We haven't found any negative repercussions to it still being present, but it is not needed as this element's content no longer updates.

For backwards compatibility, custom classes that have been added to the HTML count element are copied onto the visible, injected counter. If you previously used a custom class to change the visibility of the counter outside of the existing threshold functionality, this may no longer work as expected. The screen reader only counter does not inherit any classes.

Why these changes have been made

These changes are intended to resolve a number of issues that came up in a recent investigation into how the character count interacted with more recent versions of screen readers: #2539

Should resolve:

Current known issues

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 March 21, 2022 16:01 Inactive
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 March 21, 2022 16:22 Inactive
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 March 21, 2022 16:43 Inactive
@querkmachine
Copy link
Member Author

Regarding #2487:

My intended approach for this was to debounce the update of the character counter text until after the user had stopped typing for a period of time (like 300 milliseconds).

However, this approach conflicts with the existing Dragon Naturally Speaking bugfix; which runs a setInterval loop every one second and pushes an update to the counter if the textarea's value has been changed. This undermines the debouncing approach, as although the character counter is updating less frequently, it is still being updated, and thus queuing things to read out. It reduces the problem, but it doesn't remove it completely.

Debouncing the character counter update also makes for a bit more of a jarring experience for sighted users, as the counter text will appear to "lag" behind their typing.

Copy link
Contributor

@owenatgov owenatgov left a comment

Choose a reason for hiding this comment

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

Just had a look at the code and left 2 little comments. Looking sharp 👍🏻

I'd also add to consider squashing your commits either now or once it's out of draft as they're close enough to sit under a single commit and we're otherwise knowingly introducing a test failure into our commit history.

@querkmachine
Copy link
Member Author

@owenatgov Ta! I've squashed those first two to remove the failing test from history.

Would further commits to this branch still be separate, or is it normal to squash when the PR is completed? Wondering how the new guidance about making atomic commits (alphagov/gds-way#696) plays out.

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 March 22, 2022 15:26 Inactive
@owenatgov
Copy link
Contributor

owenatgov commented Mar 23, 2022

@querkmachine It's a tricky one. I generally play it by ear depending on how many "things" the code I'm writing includes. Things in this context being changes to the code that we could reliably ship, big or small, even if they're part of a wider bit of work so it makes sense to chunk them into one PR.

In this case my advice would be if you end up adding anything to this that isn't covered by the original commit message, make it a new commit. I think how you've split it out so far makes sense.

@querkmachine
Copy link
Member Author

Again regarding #2487, I've considered a couple of approaches to trying to fix this:

  • Debouncing the text update.
  • Adding a second, screen reader-only counter element with debounced text in it.
    • David and I think this might be verging on overkill, and isn't something we want to do if we can help it.
  • Adding debounced text to an aria-label on the counter, in an effort to see if screen readers will opt to read that over the innerText.
    • It does not. In fact, VoiceOver doesn't read out the counter at all if there's an aria-label on it. Weird!
  • Entirely remove the functionality that updates the counter on keyboard input, and rely entirely on interval-based checks.
    • This feels like a poor practice to follow, and makes the counter inherently less responsive to user input.

I'm open to any other approaches that people come up with

@querkmachine querkmachine self-assigned this Mar 25, 2022
@querkmachine
Copy link
Member Author

querkmachine commented Mar 30, 2022

Testing this PR in various AT/browser combinations (particularly those the issues were initially identified in).

Checked items work as expected or within an acceptable level, such as having non-persistent or relatively minor issues (in my opinion). Any combinations not listed haven't been tested in.

  • Character count message is repeated twice by screen readers #2485
    • JAWS 2021.2103.174 / Chrome 99
    • JAWS 2021.2103.174 / Firefox 98
      • On occassion, character count is still read out twice after the user has stopped typing.
    • JAWS 2021.2103.174 / IE 11
    • NVDA 2021.2 / Chrome 96
    • NVDA 2021.2 / Firefox 94
    • NVDA 2021.2 / IE 11
    • VoiceOver (macOS 12.3) / Firefox 98
      • On occassion, character count is still read out twice after the user has stopped typing.
    • VoiceOver (macOS 12.3) / Safari 15.4
      • Readout persistently stutters, e.g. "You have— You have n characters remaining."
      • Duplicate readout happens consistently, but only in response to certain user input. For example, if a field is focused and input is given without ever pressing backspace, the duplicate reading does not occur. If a user has pressed backspace or applied an autocorrect suggestion, then duplicate readings start to take place until the field loses focus. If focus is re-applied, no duplicates take place until backspace is pressed again.
  • Hint text for a character count is included by screen readers as part of the count message #2486
    • JAWS 2021.2103.174 / Chrome 99
      • The "You can use up to n characters" message is not read on initial focus if a field has a default value provided.
      • Neither are hints or error messages. This issue also happens on the live component. Pre-existing issue?
    • JAWS 2021.2103.174 / Firefox 98
      • If a field is focused by pointer navigation, only reads out "You can use up to n characters" message.
      • If a field is focused by keyboard navigation, reads out both "You can use up to n characters" and "You have n characters remaining" messages.
    • JAWS 2021.2103.174 / IE 11
      • If a field is focused by pointer navigation, only reads out "You can use up to n characters" message.
      • If a field is focused by keyboard navigation, reads out both "You can use up to n characters" and "You have n characters remaining" messages.
    • NVDA 2021.2 / Chrome 96
    • NVDA 2021.2 / Firefox 94
    • NVDA 2021.2 / IE 11
    • VoiceOver (macOS 12.3) / Firefox 98
    • VoiceOver (macOS 12.3) / Safari 15.4
  • Character count messages are announced by screen readers even when the count is below a set threshold #2488
    • JAWS 2021.2103.174 / Chrome 99
    • JAWS 2021.2103.174 / Firefox 98
    • JAWS 2021.2103.174 / IE 11
      • Issue still present.
    • NVDA 2021.2 / Chrome 96
    • NVDA 2021.2 / Firefox 94
    • NVDA 2021.2 / IE 11
    • VoiceOver (macOS 12.3) / Firefox 98
    • VoiceOver (macOS 12.3) / Safari 15.4
  • Multiple outdated announcements can be made when the user stops typing into the character count. #2487
    • JAWS 2021.2103.174 / Chrome 99
      • Does not work correctly on the threshold version of the counter. The counter is not read out if the input the user has provided since the last update pushed it over the threshold.
      • Works as expected on all other versions of the character counter.
    • JAWS 2021.2103.174 / Firefox 98
    • JAWS 2021.2103.174 / IE 11
    • NVDA 2021.2 / Chrome 96
    • NVDA 2021.2 / Firefox 94
    • NVDA 2021.2 / IE 11
    • VoiceOver (macOS 12.3) / Firefox 98
    • VoiceOver (macOS 12.3) / Safari 15.4

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 March 31, 2022 14:53 Inactive
@querkmachine
Copy link
Member Author

I've applied the suggestion from @36degrees (here: #2487 (comment)) for debouncing the character counter update. The counter is now not updated until 250 milliseconds after the user has stopped typing, which (mostly) successfully stops screen readers from queuing up multiple updates or attempting to read them whilst a user is still typing.

The delay before the update is made may still need tweaking based on testing. There is a need to strike a balance between immediacy of feedback for users of the visual counter and that of screen reader users.

The debounced nature of the counter now means that the tests fail too. Gotta fix that.

@querkmachine
Copy link
Member Author

querkmachine commented Apr 4, 2022

Have discussed some of the issues that came up in testing and we have decided that none of these are blockers (they are all equivalent to or improvements on the existing component, despite the flaws. Having these be documented as known issues would be useful.

The VoiceOver/Safari issue with the counter being read out twice has been opened as #2587.

The JAWS/Chrome issue with textareas with default values has been opened as #2585.

@edwardhorsford
Copy link
Contributor

I've applied the suggestion from @36degrees (here: #2487 (comment)) for debouncing the character counter update. The counter is now not updated until 250 milliseconds after the user has stopped typing, which (mostly) successfully stops screen readers from queuing up multiple updates or attempting to read them whilst a user is still typing.

The delay before the update is made may still need tweaking based on testing. There is a need to strike a balance between immediacy of feedback for users of the visual counter and that of screen reader users.

The debounced nature of the counter now means that the tests fail too. Gotta fix that.

@querkmachine do the visual updates and screen reader updates need to be tied together? Perhaps they should just be two independent elements? One hidden from screen readers, the other visually hidden.

@querkmachine
Copy link
Member Author

@querkmachine do the visual updates and screen reader updates need to be tied together? Perhaps they should just be two independent elements? One hidden from screen readers, the other visually hidden.

@edwardhorsford They don't have to be tied, strictly speaking. I discussed the idea previously with David, our accessibility specialist (mentioned in this comment), but we were worried that having multiple updating elements—some visible and others not, some debounced and others not—would be making the component JS more complex than is strictly necessary.

The change to how the visual counter updates hasn't undergone any user testing, and we were considering splitting it out if we felt it was necessary. Do you feel like it might?

@edwardhorsford
Copy link
Contributor

@querkmachine is there a review app I could try? My worry is it might impact faster typists - as 250ms would be quite a while for and you might end up with an extended period without update.

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 April 11, 2022 09:37 Inactive
@querkmachine querkmachine dismissed vanitabarrett’s stale review April 11, 2022 12:58

Decided no action on outstanding point.

@vanitabarrett
Copy link
Contributor

Tested with the latest changes (including dd564e3 ) and this seems like a huge improvement on the issues we'd previously noticed! Unfortunately I don't have access to an iOS or stock Android device to test on mobile.

Spreadsheet of testing results here: https://docs.google.com/spreadsheets/d/1i2oexwBY-xs-HmRTce9xiOSX6RYBJigeRcRQwlMiCU8/edit#gid=2015583909

@vanitabarrett
Copy link
Contributor

@querkmachine It would be good if we could get this tested in Android and iOS and record it on that spreadsheet. You might need to ask around for someone with an Android device to test 🤔

@querkmachine
Copy link
Member Author

querkmachine commented Apr 11, 2022

Have updated testing spreadsheet with results for VoiceOver / iOS 15.3 and Talkback / Android 11. Can additionally confirm that the counter seems to work with the built-in voice inputs for each OS, too.

@edwardhorsford
Copy link
Contributor

Checking the latest review app, the responsiveness (for a fast typist) is looking much better.

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 April 12, 2022 08:24 Inactive
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-2577 April 12, 2022 09:42 Inactive
Copy link
Contributor

@vanitabarrett vanitabarrett left a comment

Choose a reason for hiding this comment

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

Amazing work, this looks really good 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment