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

Use button element for entire input replacement #5609

Draft
wants to merge 7 commits into
base: spike-enhanced-file-upload
Choose a base branch
from

Conversation

patrickpatrickpatrick
Copy link
Contributor

@patrickpatrickpatrick patrickpatrickpatrick commented Jan 15, 2025

What

Instead of replacing the native input with a collection of elements, replace the native input with a button that has the replacement encapsulated within it. Involves making a "pseudo-button" that has the same styling as a regular button.

Hide the file input with display: none and tabindex = '-1'.

Why

Fixes #5612

@patrickpatrickpatrick patrickpatrickpatrick changed the base branch from main to spike-enhanced-file-upload January 15, 2025 15:03
Copy link

github-actions bot commented Jan 15, 2025

📋 Stats

File sizes

File Size
dist/govuk-frontend-development.min.css 120.03 KiB
dist/govuk-frontend-development.min.js 45.49 KiB
packages/govuk-frontend/dist/govuk/all.bundle.js 98.5 KiB
packages/govuk-frontend/dist/govuk/all.bundle.mjs 92.48 KiB
packages/govuk-frontend/dist/govuk/all.mjs 1.32 KiB
packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs 1.74 KiB
packages/govuk-frontend/dist/govuk/govuk-frontend.min.css 120.02 KiB
packages/govuk-frontend/dist/govuk/govuk-frontend.min.js 45.48 KiB
packages/govuk-frontend/dist/govuk/i18n.mjs 5.55 KiB
packages/govuk-frontend/dist/govuk/init.mjs 7.5 KiB

Modules

File Size (bundled) Size (minified)
all.mjs 87.65 KiB 43.05 KiB
accordion.mjs 26.58 KiB 13.41 KiB
button.mjs 9.09 KiB 3.78 KiB
character-count.mjs 25.39 KiB 10.9 KiB
checkboxes.mjs 7.81 KiB 3.42 KiB
error-summary.mjs 10.99 KiB 4.54 KiB
exit-this-page.mjs 20.2 KiB 10.34 KiB
file-upload.mjs 18.22 KiB 8.64 KiB
header.mjs 6.46 KiB 3.22 KiB
notification-banner.mjs 9.35 KiB 3.7 KiB
password-input.mjs 18.24 KiB 8.33 KiB
radios.mjs 6.81 KiB 2.98 KiB
service-navigation.mjs 6.44 KiB 3.26 KiB
skip-link.mjs 6.4 KiB 2.76 KiB
tabs.mjs 12.04 KiB 6.67 KiB

View stats and visualisations on the review app


Action run for 8b5dd7b

Copy link

github-actions bot commented Jan 15, 2025

JavaScript changes to npm package

diff --git a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
index 341ec36d6..ce7616fb6 100644
--- a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
+++ b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
@@ -757,9 +757,13 @@ class FileUpload extends ConfigurableComponent {
         const n = document.createElement("div");
         n.className = "govuk-file-upload-wrapper";
         const s = document.createElement("button");
-        s.className = "govuk-button govuk-button--secondary govuk-file-upload__button", s.type = "button", s.innerText = this.i18n.t("selectFilesButton"), s.addEventListener("click", this.onClick.bind(this));
+        s.classList.add("govuk-file-upload__button"), s.type = "button";
         const i = document.createElement("span");
-        i.className = "govuk-body govuk-file-upload__status", i.innerText = this.i18n.t("filesSelectedDefault"), i.setAttribute("role", "status"), n.insertAdjacentElement("beforeend", s), n.insertAdjacentElement("beforeend", i), this.$root.insertAdjacentElement("afterend", n), n.insertAdjacentElement("afterbegin", this.$root), this.$wrapper = n, this.$button = s, this.$status = i, this.$root.setAttribute("tabindex", "-1"), this.updateDisabledState(), this.observeDisabledState(), this.$root.addEventListener("change", this.onChange.bind(this)), this.$wrapper.addEventListener("drop", this.onDragLeaveOrDrop.bind(this)), document.addEventListener("dragenter", this.onDragEnter.bind(this)), document.addEventListener("dragleave", this.onDragLeaveOrDrop.bind(this))
+        i.className = "govuk-button govuk-button--secondary govuk-file-upload__pseudo-button", i.innerText = this.i18n.t("selectFilesButton");
+        const o = document.createElement("span");
+        o.className = "govuk-visually-hidden", o.innerText = ", ", s.appendChild(i), s.appendChild(o), s.addEventListener("click", this.onClick.bind(this));
+        const r = document.createElement("span");
+        r.className = "govuk-body govuk-file-upload__status", r.innerText = this.i18n.t("filesSelectedDefault"), s.appendChild(r), n.insertAdjacentElement("beforeend", s), this.$root.insertAdjacentElement("afterend", n), this.$root.setAttribute("tabindex", "-1"), this.$root.setAttribute("aria-hidden", "true"), n.insertAdjacentElement("afterbegin", this.$root), this.$wrapper = n, this.$button = s, this.$status = r, this.$root.addEventListener("change", this.onChange.bind(this)), this.updateDisabledState(), this.observeDisabledState(), this.$wrapper.addEventListener("drop", this.onDragLeaveOrDrop.bind(this)), document.addEventListener("dragenter", this.onDragEnter.bind(this)), document.addEventListener("dragleave", this.onDragLeaveOrDrop.bind(this))
     }
     onChange() {
         const t = this.$root.files.length;

Action run for 8b5dd7b

Copy link

github-actions bot commented Jan 15, 2025

Stylesheets changes to npm package

diff --git a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.css b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.css
index f1b48d569..e057b6a41 100644
--- a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.css
+++ b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.css
@@ -3397,7 +3397,7 @@ screen and (forced-colors:active) {
     background-color: #fff
 }
 
-.govuk-file-upload-wrapper--show-dropzone .govuk-file-upload__button,
+.govuk-file-upload-wrapper--show-dropzone .govuk-file-upload__pseudo-button,
 .govuk-file-upload-wrapper--show-dropzone .govuk-file-upload__status {
     pointer-events: none
 }
@@ -3413,7 +3413,7 @@ screen and (forced-colors:active) {
     opacity: 0
 }
 
-.govuk-file-upload__button {
+.govuk-file-upload__pseudo-button {
     width: auto;
     margin-bottom: 0;
     flex-grow: 0;
@@ -3425,6 +3425,53 @@ screen and (forced-colors:active) {
     margin-left: 10px
 }
 
+.govuk-file-upload__button:focus {
+    outline: none
+}
+
+.govuk-file-upload__button:focus .govuk-file-upload__pseudo-button {
+    outline: 3px solid transparent;
+    background-color: #fd0;
+    box-shadow: 0 2px 0 #0b0c0c
+}
+
+.govuk-file-upload__button:focus .govuk-file-upload__pseudo-button:hover {
+    border-color: #fd0;
+    outline: 3px solid transparent;
+    background-color: #c2c2c1;
+    box-shadow: inset 0 0 0 1px #fd0
+}
+
+.govuk-file-upload__button:active .govuk-file-upload__pseudo-button:hover {
+    background-color: #c2c2c1
+}
+
+.govuk-file-upload__button {
+    align-items: center;
+    display: flex;
+    padding: 0;
+    border: 0;
+    background-color: transparent
+}
+
+.govuk-file-upload:disabled+.govuk-file-upload__button {
+    pointer-events: none
+}
+
+.govuk-file-upload:disabled+.govuk-file-upload__button .govuk-file-upload__pseudo-button {
+    opacity: .5
+}
+
+.govuk-file-upload:disabled+.govuk-file-upload__button .govuk-file-upload__pseudo-button:hover {
+    background-color: #f3f2f1;
+    cursor: not-allowed
+}
+
+.govuk-file-upload:disabled+.govuk-file-upload__button .govuk-file-upload__pseudo-button:active {
+    top: 0;
+    box-shadow: 0 2px 0 #666
+}
+
 .govuk-footer {
     font-family: GDS Transport, arial, sans-serif;
     -webkit-font-smoothing: antialiased;

Action run for 8b5dd7b

Copy link

github-actions bot commented Jan 15, 2025

Other changes to npm package

diff --git a/packages/govuk-frontend/dist/govuk/all.bundle.js b/packages/govuk-frontend/dist/govuk/all.bundle.js
index 63161d0ec..da9b0a9e3 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.js
@@ -1681,25 +1681,32 @@
       const $wrapper = document.createElement('div');
       $wrapper.className = 'govuk-file-upload-wrapper';
       const $button = document.createElement('button');
-      $button.className = 'govuk-button govuk-button--secondary govuk-file-upload__button';
+      $button.classList.add('govuk-file-upload__button');
       $button.type = 'button';
-      $button.innerText = this.i18n.t('selectFilesButton');
+      const buttonSpan = document.createElement('span');
+      buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload__pseudo-button';
+      buttonSpan.innerText = this.i18n.t('selectFilesButton');
+      const commaSpan = document.createElement('span');
+      commaSpan.className = 'govuk-visually-hidden';
+      commaSpan.innerText = ', ';
+      $button.appendChild(buttonSpan);
+      $button.appendChild(commaSpan);
       $button.addEventListener('click', this.onClick.bind(this));
       const $status = document.createElement('span');
       $status.className = 'govuk-body govuk-file-upload__status';
       $status.innerText = this.i18n.t('filesSelectedDefault');
-      $status.setAttribute('role', 'status');
+      $button.appendChild($status);
       $wrapper.insertAdjacentElement('beforeend', $button);
-      $wrapper.insertAdjacentElement('beforeend', $status);
       this.$root.insertAdjacentElement('afterend', $wrapper);
+      this.$root.setAttribute('tabindex', '-1');
+      this.$root.setAttribute('aria-hidden', 'true');
       $wrapper.insertAdjacentElement('afterbegin', this.$root);
       this.$wrapper = $wrapper;
       this.$button = $button;
       this.$status = $status;
-      this.$root.setAttribute('tabindex', '-1');
+      this.$root.addEventListener('change', this.onChange.bind(this));
       this.updateDisabledState();
       this.observeDisabledState();
-      this.$root.addEventListener('change', this.onChange.bind(this));
       this.$wrapper.addEventListener('drop', this.onDragLeaveOrDrop.bind(this));
       document.addEventListener('dragenter', this.onDragEnter.bind(this));
       document.addEventListener('dragleave', this.onDragLeaveOrDrop.bind(this));
diff --git a/packages/govuk-frontend/dist/govuk/all.bundle.mjs b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
index 34f9a09f1..7d33c7599 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
@@ -1675,25 +1675,32 @@ class FileUpload extends ConfigurableComponent {
     const $wrapper = document.createElement('div');
     $wrapper.className = 'govuk-file-upload-wrapper';
     const $button = document.createElement('button');
-    $button.className = 'govuk-button govuk-button--secondary govuk-file-upload__button';
+    $button.classList.add('govuk-file-upload__button');
     $button.type = 'button';
-    $button.innerText = this.i18n.t('selectFilesButton');
+    const buttonSpan = document.createElement('span');
+    buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload__pseudo-button';
+    buttonSpan.innerText = this.i18n.t('selectFilesButton');
+    const commaSpan = document.createElement('span');
+    commaSpan.className = 'govuk-visually-hidden';
+    commaSpan.innerText = ', ';
+    $button.appendChild(buttonSpan);
+    $button.appendChild(commaSpan);
     $button.addEventListener('click', this.onClick.bind(this));
     const $status = document.createElement('span');
     $status.className = 'govuk-body govuk-file-upload__status';
     $status.innerText = this.i18n.t('filesSelectedDefault');
-    $status.setAttribute('role', 'status');
+    $button.appendChild($status);
     $wrapper.insertAdjacentElement('beforeend', $button);
-    $wrapper.insertAdjacentElement('beforeend', $status);
     this.$root.insertAdjacentElement('afterend', $wrapper);
+    this.$root.setAttribute('tabindex', '-1');
+    this.$root.setAttribute('aria-hidden', 'true');
     $wrapper.insertAdjacentElement('afterbegin', this.$root);
     this.$wrapper = $wrapper;
     this.$button = $button;
     this.$status = $status;
-    this.$root.setAttribute('tabindex', '-1');
+    this.$root.addEventListener('change', this.onChange.bind(this));
     this.updateDisabledState();
     this.observeDisabledState();
-    this.$root.addEventListener('change', this.onChange.bind(this));
     this.$wrapper.addEventListener('drop', this.onDragLeaveOrDrop.bind(this));
     document.addEventListener('dragenter', this.onDragEnter.bind(this));
     document.addEventListener('dragleave', this.onDragLeaveOrDrop.bind(this));
diff --git a/packages/govuk-frontend/dist/govuk/components/file-upload/_index.scss b/packages/govuk-frontend/dist/govuk/components/file-upload/_index.scss
index 34e781c51..77b01af86 100644
--- a/packages/govuk-frontend/dist/govuk/components/file-upload/_index.scss
+++ b/packages/govuk-frontend/dist/govuk/components/file-upload/_index.scss
@@ -64,7 +64,7 @@
     border: $govuk-border-width-form-element dashed $govuk-input-border-colour;
     background-color: $govuk-body-background-colour;
 
-    .govuk-file-upload__button,
+    .govuk-file-upload__pseudo-button,
     .govuk-file-upload__status {
       // When the dropzone is hovered over, make these aspects not accept
       // mouse events, so dropped files fall through to the input beneath them
@@ -85,7 +85,7 @@
     opacity: 0;
   }
 
-  .govuk-file-upload__button {
+  .govuk-file-upload__pseudo-button {
     width: auto;
     margin-bottom: 0;
     flex-grow: 0;
@@ -98,4 +98,51 @@
   }
 }
 
+.govuk-file-upload__button:focus {
+  outline: none;
+}
+
+.govuk-file-upload__button:focus .govuk-file-upload__pseudo-button {
+  outline: 3px solid transparent;
+  background-color: $govuk-focus-colour;
+  box-shadow: 0 2px 0 govuk-colour("black");
+}
+
+.govuk-file-upload__button:focus .govuk-file-upload__pseudo-button:hover {
+  border-color: $govuk-focus-colour;
+  outline: 3px solid transparent;
+  background-color: govuk-shade(govuk-colour("light-grey"), 20%);
+  box-shadow: inset 0 0 0 1px $govuk-focus-colour;
+}
+
+.govuk-file-upload__button:active .govuk-file-upload__pseudo-button:hover {
+  background-color: govuk-shade(govuk-colour("light-grey"), 20%);
+}
+
+.govuk-file-upload__button {
+  align-items: center;
+  display: flex;
+  padding: 0;
+  border: 0;
+  background-color: transparent;
+}
+
+.govuk-file-upload:disabled + .govuk-file-upload__button {
+  pointer-events: none;
+}
+
+.govuk-file-upload:disabled + .govuk-file-upload__button .govuk-file-upload__pseudo-button {
+  opacity: (0.5);
+
+  &:hover {
+    background-color: govuk-colour("light-grey");
+    cursor: not-allowed;
+  }
+
+  &:active {
+    top: 0;
+    box-shadow: 0 $govuk-border-width-form-element 0 govuk-shade(govuk-colour("white"), 60%); // s0
+  }
+}
+
 /*# sourceMappingURL=_index.scss.map */
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 87cf44235..5f1dff7f0 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
@@ -508,25 +508,32 @@
       const $wrapper = document.createElement('div');
       $wrapper.className = 'govuk-file-upload-wrapper';
       const $button = document.createElement('button');
-      $button.className = 'govuk-button govuk-button--secondary govuk-file-upload__button';
+      $button.classList.add('govuk-file-upload__button');
       $button.type = 'button';
-      $button.innerText = this.i18n.t('selectFilesButton');
+      const buttonSpan = document.createElement('span');
+      buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload__pseudo-button';
+      buttonSpan.innerText = this.i18n.t('selectFilesButton');
+      const commaSpan = document.createElement('span');
+      commaSpan.className = 'govuk-visually-hidden';
+      commaSpan.innerText = ', ';
+      $button.appendChild(buttonSpan);
+      $button.appendChild(commaSpan);
       $button.addEventListener('click', this.onClick.bind(this));
       const $status = document.createElement('span');
       $status.className = 'govuk-body govuk-file-upload__status';
       $status.innerText = this.i18n.t('filesSelectedDefault');
-      $status.setAttribute('role', 'status');
+      $button.appendChild($status);
       $wrapper.insertAdjacentElement('beforeend', $button);
-      $wrapper.insertAdjacentElement('beforeend', $status);
       this.$root.insertAdjacentElement('afterend', $wrapper);
+      this.$root.setAttribute('tabindex', '-1');
+      this.$root.setAttribute('aria-hidden', 'true');
       $wrapper.insertAdjacentElement('afterbegin', this.$root);
       this.$wrapper = $wrapper;
       this.$button = $button;
       this.$status = $status;
-      this.$root.setAttribute('tabindex', '-1');
+      this.$root.addEventListener('change', this.onChange.bind(this));
       this.updateDisabledState();
       this.observeDisabledState();
-      this.$root.addEventListener('change', this.onChange.bind(this));
       this.$wrapper.addEventListener('drop', this.onDragLeaveOrDrop.bind(this));
       document.addEventListener('dragenter', this.onDragEnter.bind(this));
       document.addEventListener('dragleave', this.onDragLeaveOrDrop.bind(this));
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 253fa0afd..f8d999539 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
@@ -502,25 +502,32 @@ class FileUpload extends ConfigurableComponent {
     const $wrapper = document.createElement('div');
     $wrapper.className = 'govuk-file-upload-wrapper';
     const $button = document.createElement('button');
-    $button.className = 'govuk-button govuk-button--secondary govuk-file-upload__button';
+    $button.classList.add('govuk-file-upload__button');
     $button.type = 'button';
-    $button.innerText = this.i18n.t('selectFilesButton');
+    const buttonSpan = document.createElement('span');
+    buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload__pseudo-button';
+    buttonSpan.innerText = this.i18n.t('selectFilesButton');
+    const commaSpan = document.createElement('span');
+    commaSpan.className = 'govuk-visually-hidden';
+    commaSpan.innerText = ', ';
+    $button.appendChild(buttonSpan);
+    $button.appendChild(commaSpan);
     $button.addEventListener('click', this.onClick.bind(this));
     const $status = document.createElement('span');
     $status.className = 'govuk-body govuk-file-upload__status';
     $status.innerText = this.i18n.t('filesSelectedDefault');
-    $status.setAttribute('role', 'status');
+    $button.appendChild($status);
     $wrapper.insertAdjacentElement('beforeend', $button);
-    $wrapper.insertAdjacentElement('beforeend', $status);
     this.$root.insertAdjacentElement('afterend', $wrapper);
+    this.$root.setAttribute('tabindex', '-1');
+    this.$root.setAttribute('aria-hidden', 'true');
     $wrapper.insertAdjacentElement('afterbegin', this.$root);
     this.$wrapper = $wrapper;
     this.$button = $button;
     this.$status = $status;
-    this.$root.setAttribute('tabindex', '-1');
+    this.$root.addEventListener('change', this.onChange.bind(this));
     this.updateDisabledState();
     this.observeDisabledState();
-    this.$root.addEventListener('change', this.onChange.bind(this));
     this.$wrapper.addEventListener('drop', this.onDragLeaveOrDrop.bind(this));
     document.addEventListener('dragenter', this.onDragEnter.bind(this));
     document.addEventListener('dragleave', this.onDragLeaveOrDrop.bind(this));
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 1ddbc3dc5..909f51397 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
@@ -31,25 +31,32 @@ class FileUpload extends ConfigurableComponent {
     const $wrapper = document.createElement('div');
     $wrapper.className = 'govuk-file-upload-wrapper';
     const $button = document.createElement('button');
-    $button.className = 'govuk-button govuk-button--secondary govuk-file-upload__button';
+    $button.classList.add('govuk-file-upload__button');
     $button.type = 'button';
-    $button.innerText = this.i18n.t('selectFilesButton');
+    const buttonSpan = document.createElement('span');
+    buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload__pseudo-button';
+    buttonSpan.innerText = this.i18n.t('selectFilesButton');
+    const commaSpan = document.createElement('span');
+    commaSpan.className = 'govuk-visually-hidden';
+    commaSpan.innerText = ', ';
+    $button.appendChild(buttonSpan);
+    $button.appendChild(commaSpan);
     $button.addEventListener('click', this.onClick.bind(this));
     const $status = document.createElement('span');
     $status.className = 'govuk-body govuk-file-upload__status';
     $status.innerText = this.i18n.t('filesSelectedDefault');
-    $status.setAttribute('role', 'status');
+    $button.appendChild($status);
     $wrapper.insertAdjacentElement('beforeend', $button);
-    $wrapper.insertAdjacentElement('beforeend', $status);
     this.$root.insertAdjacentElement('afterend', $wrapper);
+    this.$root.setAttribute('tabindex', '-1');
+    this.$root.setAttribute('aria-hidden', 'true');
     $wrapper.insertAdjacentElement('afterbegin', this.$root);
     this.$wrapper = $wrapper;
     this.$button = $button;
     this.$status = $status;
-    this.$root.setAttribute('tabindex', '-1');
+    this.$root.addEventListener('change', this.onChange.bind(this));
     this.updateDisabledState();
     this.observeDisabledState();
-    this.$root.addEventListener('change', this.onChange.bind(this));
     this.$wrapper.addEventListener('drop', this.onDragLeaveOrDrop.bind(this));
     document.addEventListener('dragenter', this.onDragEnter.bind(this));
     document.addEventListener('dragleave', this.onDragLeaveOrDrop.bind(this));

Action run for 8b5dd7b

@patrickpatrickpatrick patrickpatrickpatrick changed the title use output Use button element for entire 'file upload' replacement Jan 16, 2025
@patrickpatrickpatrick patrickpatrickpatrick changed the title Use button element for entire 'file upload' replacement Use button element for entire input replacement Jan 16, 2025
@selfthinker
Copy link

selfthinker commented Jan 16, 2025

I've done some testing with assistive technologies. Details are in the testing spreadsheet (in the '16 Jan 2025' tab).
Here is a summary of my findings.

  • The focus style of the fake button is currently not the same as our standard secondary button.
  • There is no visible focus at all when using Windows High Contrast Mode or changing colours in Firefox.
  • I can confirm that this version of the component works with Dragon.
  • Most of the screen reader and browser combinations are pretty consistent, with a few exceptions.
  • There is no pause between the fake button text and the feedback area. I'd suggest to add a visually hidden comma between them. It's not that bad, but it also makes sense for those people who use their own styles or disable styles. When you disable styles there is not even a space. So, ideally also add a visually hidden space after the comma.
  • NVDA in Firefox never mentions the file name after a file has been selected. It only reads the label instead. I think that is because the screen reader focus is at the label for whatever reason. You can discover the file name when you navigate further.
  • VoiceOver on macOS in Safari seems to read the hidden file input after selecting a file. (It says: "no file selected, [label], [hint], file upload button".) It usually says "no file selected" (which is what the native file input says in Safari when no file is selected), but sometimes it happened that it read the file name instead. Interestingly, the native file input also says "no file selected" after selecting a file, so it's not a bug that we have introduced. It's possible the JS gets the values correctly but that the values that Safari provides are just incorrect.
  • It happened multiple times during testing with most screen readers that after selecting a file they either read "no file chosen" or the previously selected file. Could there be a race condition going on?

I suspect the only items from that list that are potentially gnarly are the two screen reader issues. We should definitely try to fix them for a bit. But the VO macOS / Safari issue has the lowest priority because of the pre-existing issue with the native input. It's worth trying to isolate the issue with NVDA to see where the issue comes from. It's possible that it's a bug in Firefox or NVDA.
If we cannot fix either of these issues, it's worth googling if there already is a bug report about that behaviour and if there isn't, report it ourselves.

@patrickpatrickpatrick
Copy link
Contributor Author

patrickpatrickpatrick commented Jan 17, 2025

Addressed a few comments:

  • focus state (including the focus state box shadow, style when the button is focus and hovered and style when the button is active and focused) for pseudo button now same as secondary button
  • added transparent outlines on focus for pseudo button for high contrast mode
  • visually hidden <span>, </span> added between pseudo button and text to ensure gap between announcement of each aspect of the button

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.

3 participants