Change how live region works with API key JS

Includes implementation of new code on Reply-to
email addresses page.

The existing code put the live region on the
module element so the id and button were
read out when the state changed.

The report from the Digital Accessibility Centre
(DAC) said screenreader users were confused by the
content changing because it wasn't announced.

These changes attempt to make the state changes
clearer by:
1. moving the live region out into a separate
  element so we can better control what is
  announced
2. adding hidden text around to the button and text
  above (sometimes the id, sometimes the 'Copied
  to clipboard' text) to give more context

When the id is copied to clipboard, the button
changes but this is not announced as the
live-region text takes precedence (due to being
set to 'assertive'). Because of this, hidden text
has been added in change 2 to explain what the new
button does.
This commit is contained in:
Tom Byers
2020-08-19 10:47:11 +01:00
parent 19ce1bd43a
commit 7fd034a83f
4 changed files with 44 additions and 17 deletions

View File

@@ -6,13 +6,24 @@
Modules.ApiKey = function() {
const states = {
'keyVisible': (key, thing) => `
<span class="api-key__key">${key}</span>
<input type='button' class='govuk-button govuk-button--secondary api-key__button--copy' value='Copy ${thing} to clipboard' />
'keyVisible': (options) => `
<span class="api-key__key">
${options.keyLabel ? '<span class="govuk-visually-hidden">' + options.thing + ': </span>' : ''}${options.key}
</span>
<span class="api-key__notice govuk-visually-hidden" aria-live="assertive">
${options.onload ? '' : options.thing + ' returned to page, press button to copy to clipboard'}
</span>
<button class="govuk-button govuk-button--secondary api-key__button--copy">
Copy ${options.thing} to clipboard${options.name ? '<span class="govuk-visually-hidden"> for ' + options.name + '</span>' : ''}
</button>
`,
'keyCopied': thing => `
<span class="api-key__key">Copied to clipboard</span>
<input type='button' class='govuk-button govuk-button--secondary api-key__button--show' value='Show ${thing}' />
'keyCopied': (options) => `
<span class="api-key__notice" aria-live="assertive">
<span class="govuk-visually-hidden">${options.thing} </span>Copied to clipboard<span class="govuk-visually-hidden">, press button to show in page</span>
</span>
<button class="govuk-button govuk-button--secondary api-key__button--show">
Show ${options.thing}${options.name ? '<span class="govuk-visually-hidden"> for ' + options.name + '</span>' : ''}
</button>
`
};
@@ -30,24 +41,38 @@
this.start = function(component) {
const $component = $(component),
key = $component.data('key'),
thing = $component.data('thing');
stateOptions = {
key: $component.data('key'),
thing: $component.data('thing')
},
name = $component.data('name');
// if the name is distinct from the thing:
// - it will be used in the rendering
// - the key won't be identified by a heading so needs its own label
if (name !== stateOptions.thing) {
stateOptions.name = name;
stateOptions.keyLabel = true;
}
$component
.addClass('api-key')
.css('min-height', $component.height())
.html(states.keyVisible(key, thing))
.attr('aria-live', 'polite')
.html(states.keyVisible($.extend({ 'onload': true }, stateOptions)))
.on(
'click', '.api-key__button--copy', () =>
this.copyKey(
$('.api-key__key', component)[0], () =>
$component.html(states.keyCopied(thing))
$component
.html(states.keyCopied(stateOptions))
.find('.govuk-button').focus()
)
)
.on(
'click', '.api-key__button--show', () =>
$component.html(states.keyVisible(key, thing))
$component
.html(states.keyVisible(stateOptions))
.find('.govuk-button').focus()
);
if ('stickAtBottomWhenScrolling' in GOVUK) {