-
Notifications
You must be signed in to change notification settings - Fork 338
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
[SPIKE] Move focus and announce status on selection #5730
Closed
romaricpascal
wants to merge
3
commits into
spike-enhanced-file-upload
from
spike-focus-fix-announce-status
Closed
[SPIKE] Move focus and announce status on selection #5730
romaricpascal
wants to merge
3
commits into
spike-enhanced-file-upload
from
spike-focus-fix-announce-status
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
After selecting a file, JAWS announces the accessible name of the button as it was before selecting. Sometimes this is the last announcement, which can make it confusing for users as the last thing they'll hear is the wrong state (potentially 'No file chosen' if it's the first time they use the component). Moving the focus to another element than the button before picking and explicitely focusing the button once back seems to consistently let JAWS announce the correct state of the component.
This'll let us not forget that we have a fix for JAWS in place. Testing requires us to trigger our own `focusin` event as Puppeteer does not seem to support automatic focus/blur events: puppeteer/puppeteer#1462
Adds an automatic announcement of the status after users pick a file. This should reassure JAWS users that their selection has been taken into account, as JAWS announces the accessible name of the button before the file picker was open, sometimes without re-announcing afterwards the accessible name once a file is picked.
📋 StatsFile sizes
Modules
View stats and visualisations on the review app Action run for 9ba42b0 |
JavaScript changes to npm packagediff --git a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
index f6220464f..64298272f 100644
--- a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
+++ b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
@@ -769,7 +769,7 @@ class FileUpload extends ConfigurableComponent {
const o = this.$input.getAttribute("aria-describedby");
o && s.setAttribute("aria-describedby", o);
const r = document.createElement("span");
- r.className = "govuk-body govuk-file-upload-button__status", r.innerText = this.i18n.t("noFileChosen"), s.appendChild(r);
+ r.className = "govuk-body govuk-file-upload-button__status", r.setAttribute("aria-live", "polite"), r.innerText = this.i18n.t("noFileChosen"), s.appendChild(r);
const a = document.createElement("span");
a.className = "govuk-visually-hidden", a.innerText = ", ", a.id = `${this.id}-comma`, s.appendChild(a);
const l = document.createElement("span");
@@ -779,7 +779,7 @@ class FileUpload extends ConfigurableComponent {
const u = document.createElement("span");
u.className = "govuk-body govuk-file-upload-button__instruction", u.innerText = this.i18n.t("dropInstruction"), l.appendChild(u), s.appendChild(l), s.setAttribute("aria-labelledby", `${i.id} ${a.id} ${s.id}`), s.addEventListener("click", this.onClick.bind(this)), s.addEventListener("dragover", (t => {
t.preventDefault()
- })), this.$root.insertAdjacentElement("afterbegin", s), this.$input.setAttribute("tabindex", "-1"), this.$input.setAttribute("aria-hidden", "true"), this.$button = s, this.$status = r, this.$input.addEventListener("change", this.onChange.bind(this)), this.updateDisabledState(), this.observeDisabledState(), this.$announcements = document.createElement("span"), this.$announcements.classList.add("govuk-file-upload-announcements"), this.$announcements.classList.add("govuk-visually-hidden"), this.$announcements.setAttribute("aria-live", "assertive"), this.$root.insertAdjacentElement("afterend", this.$announcements), this.$button.addEventListener("drop", this.onDrop.bind(this)), document.addEventListener("dragenter", this.updateDropzoneVisibility.bind(this)), document.addEventListener("dragenter", (() => {
+ })), this.$root.insertAdjacentElement("afterbegin", s), this.$input.setAttribute("tabindex", "-1"), this.$input.setAttribute("aria-hidden", "true"), this.$focusMagnet = document.createElement("span"), this.$focusMagnet.setAttribute("tabindex", "-1"), this.$root.appendChild(this.$focusMagnet), this.$button = s, this.$status = r, this.$input.addEventListener("change", this.onChange.bind(this)), this.updateDisabledState(), this.observeDisabledState(), this.$announcements = document.createElement("span"), this.$announcements.classList.add("govuk-file-upload-announcements"), this.$announcements.classList.add("govuk-visually-hidden"), this.$announcements.setAttribute("aria-live", "assertive"), this.$root.insertAdjacentElement("afterend", this.$announcements), this.$button.addEventListener("drop", this.onDrop.bind(this)), document.addEventListener("dragenter", this.updateDropzoneVisibility.bind(this)), document.addEventListener("dragenter", (() => {
this.enteredAnotherElement = !0
})), document.addEventListener("dragleave", (() => {
this.enteredAnotherElement || this.$button.disabled || (this.hideDraggingState(), this.$announcements.innerText = this.i18n.t("leftDropZone")), this.enteredAnotherElement = !1
@@ -795,7 +795,7 @@ class FileUpload extends ConfigurableComponent {
this.$button.classList.remove("govuk-file-upload-button--dragging")
}
onDrop(t) {
- t.preventDefault(), t.dataTransfer && isContainingFiles(t.dataTransfer) && (this.$input.files = t.dataTransfer.files, this.$input.dispatchEvent(new CustomEvent("change")), this.$announcements.innerText = this.$status.innerText, this.hideDraggingState())
+ t.preventDefault(), t.dataTransfer && isContainingFiles(t.dataTransfer) && (this.$input.files = t.dataTransfer.files, this.$input.dispatchEvent(new CustomEvent("change")), this.hideDraggingState())
}
onChange() {
const t = this.$input.files.length;
@@ -812,7 +812,13 @@ class FileUpload extends ConfigurableComponent {
return t
}
onClick() {
- this.$input.click()
+ this.$focusMagnet.focus({
+ preventScroll: !0
+ }), document.addEventListener("focusin", (() => this.$button.focus({
+ preventScroll: !0
+ })), {
+ once: !0
+ }), this.$input.click()
}
observeDisabledState() {
new MutationObserver((t => {
Action run for 9ba42b0 |
Other changes to npm packagediff --git a/packages/govuk-frontend/dist/govuk/all.bundle.js b/packages/govuk-frontend/dist/govuk/all.bundle.js
index b57e1a9a6..47c042a59 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.js
@@ -1713,6 +1713,7 @@
}
const $status = document.createElement('span');
$status.className = 'govuk-body govuk-file-upload-button__status';
+ $status.setAttribute('aria-live', 'polite');
$status.innerText = this.i18n.t('noFileChosen');
$button.appendChild($status);
const commaSpan = document.createElement('span');
@@ -1740,6 +1741,9 @@
this.$root.insertAdjacentElement('afterbegin', $button);
this.$input.setAttribute('tabindex', '-1');
this.$input.setAttribute('aria-hidden', 'true');
+ this.$focusMagnet = document.createElement('span');
+ this.$focusMagnet.setAttribute('tabindex', '-1');
+ this.$root.appendChild(this.$focusMagnet);
this.$button = $button;
this.$status = $status;
this.$input.addEventListener('change', this.onChange.bind(this));
@@ -1804,7 +1808,6 @@
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
this.$input.files = event.dataTransfer.files;
this.$input.dispatchEvent(new CustomEvent('change'));
- this.$announcements.innerText = this.$status.innerText;
this.hideDraggingState();
}
}
@@ -1835,6 +1838,14 @@
return $label;
}
onClick() {
+ this.$focusMagnet.focus({
+ preventScroll: true
+ });
+ document.addEventListener('focusin', () => this.$button.focus({
+ preventScroll: true
+ }), {
+ once: true
+ });
this.$input.click();
}
observeDisabledState() {
diff --git a/packages/govuk-frontend/dist/govuk/all.bundle.mjs b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
index bd59d9bb4..f735769e7 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
@@ -1707,6 +1707,7 @@ class FileUpload extends ConfigurableComponent {
}
const $status = document.createElement('span');
$status.className = 'govuk-body govuk-file-upload-button__status';
+ $status.setAttribute('aria-live', 'polite');
$status.innerText = this.i18n.t('noFileChosen');
$button.appendChild($status);
const commaSpan = document.createElement('span');
@@ -1734,6 +1735,9 @@ class FileUpload extends ConfigurableComponent {
this.$root.insertAdjacentElement('afterbegin', $button);
this.$input.setAttribute('tabindex', '-1');
this.$input.setAttribute('aria-hidden', 'true');
+ this.$focusMagnet = document.createElement('span');
+ this.$focusMagnet.setAttribute('tabindex', '-1');
+ this.$root.appendChild(this.$focusMagnet);
this.$button = $button;
this.$status = $status;
this.$input.addEventListener('change', this.onChange.bind(this));
@@ -1798,7 +1802,6 @@ class FileUpload extends ConfigurableComponent {
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
this.$input.files = event.dataTransfer.files;
this.$input.dispatchEvent(new CustomEvent('change'));
- this.$announcements.innerText = this.$status.innerText;
this.hideDraggingState();
}
}
@@ -1829,6 +1832,14 @@ class FileUpload extends ConfigurableComponent {
return $label;
}
onClick() {
+ this.$focusMagnet.focus({
+ preventScroll: true
+ });
+ document.addEventListener('focusin', () => this.$button.focus({
+ preventScroll: true
+ }), {
+ once: true
+ });
this.$input.click();
}
observeDisabledState() {
diff --git a/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js b/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js
index 6c37a8243..1121c9b63 100644
--- a/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js
@@ -540,6 +540,7 @@
}
const $status = document.createElement('span');
$status.className = 'govuk-body govuk-file-upload-button__status';
+ $status.setAttribute('aria-live', 'polite');
$status.innerText = this.i18n.t('noFileChosen');
$button.appendChild($status);
const commaSpan = document.createElement('span');
@@ -567,6 +568,9 @@
this.$root.insertAdjacentElement('afterbegin', $button);
this.$input.setAttribute('tabindex', '-1');
this.$input.setAttribute('aria-hidden', 'true');
+ this.$focusMagnet = document.createElement('span');
+ this.$focusMagnet.setAttribute('tabindex', '-1');
+ this.$root.appendChild(this.$focusMagnet);
this.$button = $button;
this.$status = $status;
this.$input.addEventListener('change', this.onChange.bind(this));
@@ -631,7 +635,6 @@
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
this.$input.files = event.dataTransfer.files;
this.$input.dispatchEvent(new CustomEvent('change'));
- this.$announcements.innerText = this.$status.innerText;
this.hideDraggingState();
}
}
@@ -662,6 +665,14 @@
return $label;
}
onClick() {
+ this.$focusMagnet.focus({
+ preventScroll: true
+ });
+ document.addEventListener('focusin', () => this.$button.focus({
+ preventScroll: true
+ }), {
+ once: true
+ });
this.$input.click();
}
observeDisabledState() {
diff --git a/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs
index 307cbbd67..1199e11ab 100644
--- a/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs
@@ -534,6 +534,7 @@ class FileUpload extends ConfigurableComponent {
}
const $status = document.createElement('span');
$status.className = 'govuk-body govuk-file-upload-button__status';
+ $status.setAttribute('aria-live', 'polite');
$status.innerText = this.i18n.t('noFileChosen');
$button.appendChild($status);
const commaSpan = document.createElement('span');
@@ -561,6 +562,9 @@ class FileUpload extends ConfigurableComponent {
this.$root.insertAdjacentElement('afterbegin', $button);
this.$input.setAttribute('tabindex', '-1');
this.$input.setAttribute('aria-hidden', 'true');
+ this.$focusMagnet = document.createElement('span');
+ this.$focusMagnet.setAttribute('tabindex', '-1');
+ this.$root.appendChild(this.$focusMagnet);
this.$button = $button;
this.$status = $status;
this.$input.addEventListener('change', this.onChange.bind(this));
@@ -625,7 +629,6 @@ class FileUpload extends ConfigurableComponent {
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
this.$input.files = event.dataTransfer.files;
this.$input.dispatchEvent(new CustomEvent('change'));
- this.$announcements.innerText = this.$status.innerText;
this.hideDraggingState();
}
}
@@ -656,6 +659,14 @@ class FileUpload extends ConfigurableComponent {
return $label;
}
onClick() {
+ this.$focusMagnet.focus({
+ preventScroll: true
+ });
+ document.addEventListener('focusin', () => this.$button.focus({
+ preventScroll: true
+ }), {
+ once: true
+ });
this.$input.click();
}
observeDisabledState() {
diff --git a/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs b/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs
index 482b1798c..b437df197 100644
--- a/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs
@@ -55,6 +55,7 @@ class FileUpload extends ConfigurableComponent {
}
const $status = document.createElement('span');
$status.className = 'govuk-body govuk-file-upload-button__status';
+ $status.setAttribute('aria-live', 'polite');
$status.innerText = this.i18n.t('noFileChosen');
$button.appendChild($status);
const commaSpan = document.createElement('span');
@@ -82,6 +83,9 @@ class FileUpload extends ConfigurableComponent {
this.$root.insertAdjacentElement('afterbegin', $button);
this.$input.setAttribute('tabindex', '-1');
this.$input.setAttribute('aria-hidden', 'true');
+ this.$focusMagnet = document.createElement('span');
+ this.$focusMagnet.setAttribute('tabindex', '-1');
+ this.$root.appendChild(this.$focusMagnet);
this.$button = $button;
this.$status = $status;
this.$input.addEventListener('change', this.onChange.bind(this));
@@ -146,7 +150,6 @@ class FileUpload extends ConfigurableComponent {
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
this.$input.files = event.dataTransfer.files;
this.$input.dispatchEvent(new CustomEvent('change'));
- this.$announcements.innerText = this.$status.innerText;
this.hideDraggingState();
}
}
@@ -177,6 +180,14 @@ class FileUpload extends ConfigurableComponent {
return $label;
}
onClick() {
+ this.$focusMagnet.focus({
+ preventScroll: true
+ });
+ document.addEventListener('focusin', () => this.$button.focus({
+ preventScroll: true
+ }), {
+ once: true
+ });
this.$input.click();
}
observeDisabledState() {
Action run for 9ba42b0 |
Closing in favour of #5729, which provides a better experience. |
1 task
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Combines #5729 and #5726 to cater for JAWS + Firefox still announcing the accessible name of the button before the file picker is open.