Problem/Motivation

When @cboyden's team did an assistive tech walkthrough of Media Library for #2834729: [META] Roadmap to stabilize Media Library using NVDA on Firefox, we discovered that, when a user attempts to upload a file type that is not allowed in the media library modal, the resulting error message that is provided is not read by the screenreader.

This is a problem because the user has no idea that there is an error, or what the error is, and the cannot proceed until they fix it.

This interaction can be viewed on the video recording of the September 29, 2019 walkthrough of Media Library at around minute 22.

Proposed resolution

The suspicion is that the container holding the error message is created dynamically when the error is triggered. Instead, the container for it needs to exist and be empty before there is an error, then populated with the error if an error is triggered.

Note that this is very similar to #3087305: Form validation error messages within the Media Library widget are not read by the screenreader, and the solution is likely the same or similar.

Remaining tasks

  • Adjust the way the error message container is placed and the message is added to it.

User interface changes

None anticipated.

API changes

None anticipated.

Data model changes

None anticipated.

Release notes snippet

TBD

Issue fork drupal-3087385

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

rainbreaw created an issue. See original summary.

andrewmacpherson’s picture

This relates to WCAG "Error identification" at level A, and "Error suggestion" at level AA. So far we've been treating WCAG level A as major/must-have.

We are SO close to marking Media Library as a stable module, and it was only filed at the eleventh hour prior to alpha week. Treating it as a must-have stable blocker will throw a serious spanner in the works. The release managers have previously indicated that accessibility bugs are eligible for inclusion after marking a core alpha release.

I'll bring this to the release managers' attention in #2834729: [META] Roadmap to stabilize Media Library.

andrewmacpherson’s picture

Adding credit for @cboyden, whose team found the bug.

oknate’s picture

I'm thinking we might be able to just change this (changing polite to assertive):

Before:

          $(this)
            .closest('div.js-form-managed-file')
            .prepend(
              `<div class="messages messages--error file-upload-js-error" aria-live="polite">${error}</div>`,
            );

After:

          $(this)
            .closest('div.js-form-managed-file')
            .prepend(
              `<div class="messages messages--error file-upload-js-error" aria-live="assertive">${error}</div>`,
            );

Although perhaps having a messages element there beforehand is more proper.

Note, this code is in /core/modules/file/file.es6.js, so this bug is more general that media library.

cboyden’s picture

@oknate if the container that has the aria-live role is not present on page load, the content of the error will not be read out by the screenreader. The container should be present and empty, and the error added to it.

bnjmnm’s picture

I tried the approach in #5 and it did not work, unfortunately.

Patch #4 for this issue #3087305: Form validation error messages within the Media Library widget are not read by the screenreader addresses this issue. The overall issue may be going with a different approach, but it could potentially be cherry picked for a fix on this one. Argh, this is not correct. That patch works for errors with the oembed form, not file upload. Sorry for the noise.

oknate’s picture

This patch works for me using Safari + VoiceOver.

Note, I tried to do this properly, adding an aria-live region on page load and then appended the error and it never read it out and then I tried again, I switched the wrapper to a role="alert" and did the same thing and it never read it out, but then I simply added Drupal.announce worked like a charm, it announced the error right away.

The "right" way didn't work:
the proper way didn't work

oknate’s picture

Status: Active » Needs review
oknate’s picture

#8 can be tested, but I need to add a dependency on drupal.announce in the library that holds file.js

phenaproxima’s picture

Component: media system » file.module

The patch is currently targeting the File module's JavaScript, so I don't think we can honestly call this a problem with the media system. ;-)

phenaproxima’s picture

Tagging for accessibility review.

oknate’s picture

rainbreaw’s picture

I tested this with VoiceOver in MacOSX on both Safari and Chrome.

Safari:
It works, except that we don't hear "error message" first to help us know that this is, in fact, an error message. Instead, I'm hearing "add files," and then the error. This is likely to be confusing.

Chrome:
It doesn't work. Given that at this time it is typically understood that VoiceOver should be used with Safari, this is an unlikely real-world use case. It does, however, concern me that there may be other instances where this doesn't work, so I would like to loop @cboyden in to request that they review this on their team, as well.

oknate’s picture

This patch uses Drupal.message instead of a custom rolled output:

-          $(this).closest('div.js-form-managed-file').prepend('<div class="messages messages--error file-upload-js-error" aria-live="polite">' + error + '</div>');
-          Drupal.announce(error, 'assertive');
+          var $messages = new Drupal.Message($messageWrapper[0]);
+          $messages.clear();
+          var $messagesId = $messages.add(error, { 'type': 'error', 'priority': 'assertive' });
+          $('#' + $messagesId).addClass('.file-upload-js-error');

This will allow it to inherit fixes to Drupal.Message and Drupal.announce.

Re: except that we don't hear "error message", this is an issue with Drupal.Message and Drupal.announce. I attempted to add the same visually hidden h2 with the "Error message" text, but I think it's better to handle this in a separate issue, since this is the case with all messages output through the javascript Drupal.Message as well. It doesn't happen with the other issue about alternative text because the message comes from the back end and it pulls all the text including the visually hidden text.

#3089402: Drupal.Message should add 'Error message' prefixed to Drupal.announce error messages

I wasn't able to fix it working in Chrome yet. I think it starts to read the message and then it's interrupted by "close dialog"

oknate’s picture

I ran patch through 'yarn prettier' that reformats the code.

The last submitted patch, 15: 3087385-15.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 16: 3087385-16.patch, failed testing. View results

andrewmacpherson’s picture

#15:

I attempted to add the same visually hidden h2 with the "Error message" text

The messages dynamically inserted by Drupal.message intentionally don't have the same H2 as the messages which are present in a full page load. This is by design, and you can find the arguments in the issue which originally added the drupal.message library. The reason is that the library can't know if H2 is an appropriate heading level, at the point where it is inserted. When inserting a heading dynamically, it effectively re-parents all content following it, until another heading of the same or higher priority. That's potentially very disruptive to the document outline for the page as a whole, so drupal.message doesn't add headings.

Instead, it's up to module developers to decide whether a heading is appropriate for their dynamic JS messages, and include the heading in a pre-existing message area.

I don't think a H2 is appropriate for the media library dialog; the messages are just being inserted near the start of the dialog content.

The server-side messages in a full page load have the H2 because it's a Drupal block. These can only be inserted in theme regions, and most themes have an appropriate theme region. We assume the site builder or themer will place this block wisely. (Aside: since layout builder was added, I'm not sure the assumption of H2 for blocks holds true any more.)

oknate’s picture

1) Fixing the test.
2) Adding the prefix, but with a span instead of an h2. Andrew had suggested using just 'Error' instead of 'Error message' for the prefixed text, but for now I'm leaving it 'Error message', since the backend is using 'Error message' in the H2, and message.es6.js has this:

    /**
     * Provide an object containing the available message types.
     *
     * @return {Object}
     *   An object containing message type strings.
     */
    static getMessageTypeLabels() {
      return {
        status: Drupal.t('Status message'),
        error: Drupal.t('Error message'),
        warning: Drupal.t('Warning message'),
      };
    }

We change the output in this use case to Drupal.t('Error') if there's consensus to shorten it. Since the beta deadline is approaching, perhaps it's best to leave it to this other issue: #3089402: Drupal.Message should add 'Error message' prefixed to Drupal.announce error messages

oknate’s picture

Status: Needs work » Needs review
bnjmnm’s picture

Status: Needs review » Needs work

Looks like that most recent patch has ~200k of extra gunk in it

  1. +++ b/core/modules/file/file.es6.js
    @@ -24,6 +24,19 @@
    +            .closest('div.js-form-managed-file')
    
    @@ -156,15 +169,17 @@
    
    

    The div part shouldn't be necessary in these various instances of div.js-form-managed-file. If the div is needed there may be another issue going on that should be addressed.

  2. +++ b/core/modules/file/file.es6.js
    @@ -24,6 +24,19 @@
    +          const $wrapper = $('<div data-drupal-messages></div>');
    

    It's preferable to not use a plain markup string

    An explanation of a jQuery alternative - using self closing tags and adding attributes as part of an object literal - can be found at https://api.jquery.com/jQuery/#entry-examples-1
    In this case it would be something like

    $wrapper = $( '<div/>', {
      'data-drupal-messages': '',
    })
    

When the extra unrelated stuff is cleaned out of the patch I'll have a closer look, but it's looking good so far.

oknate’s picture

Fixing patch noise and #22.2.

For #22.1, I change this and then changed it back. All throughout file.es6.js it's using 'div.js-form-managed-file', so I think we should stay consistent with the rest of the file, and then fix this in a separate issue. What do you think?

oknate’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 23: 3087385-23.patch, failed testing. View results

oknate’s picture

xjm’s picture

Priority: Normal » Major
phenaproxima’s picture

Issue tags: +Amsterdam2019

Tagging this issue to be worked on at DrupalCon Amsterdam.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nishantghetiya made their first commit to this issue’s fork.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
FileSize
149 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

mgifford’s picture

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.