carbon-design-system / carbon

A design system built by IBM
https://www.carbondesignsystem.com
Apache License 2.0
7.85k stars 1.81k forks source link

[a11y]: inline and toast notifications does not take keyboard focus #15907

Closed mbgower closed 1 week ago

mbgower commented 8 months ago

Package

@carbon/react

Browser

Chrome

Operating System

MacOS

Package version

https://react.carbondesignsystem.com/?path=/story/components-notifications-inline--default#storybook-preview-wrapper

React version

Storybook

Automated testing tool and ruleset

n/a

Assistive technology

untested

Description

When using the inline notification in storybook, it never receives a focus indicator (and does not seem to receive keyboard focus either).

The cause appears to be that there is a -1 tabindex set on the close button, so it will never take focus.

image

The same issue occurs with the Toast notification example

WCAG 2.1 Violation

2.4.7 Focus Visible; 2.1.1 keyboard... Take your pick!

Reproduction/example

https://react.carbondesignsystem.com/iframe.html?id=components-notifications-inline--default&viewMode=story

Steps to reproduce

  1. Navigate to inline loading in storybook
  2. Attempt to reach the close (x) button by navigating by keyboard

At no point will the x take focus.

Code of Conduct

tay1orjones commented 7 months ago

@mbgower this is intentional because these get a role of alert, log, or status which aren't supposed to contain anything interactive and won't receive focus. So there's not really a way for a screenreader to readily get to that close button. So we keep the close button out of the tab order, but it's still visible as an affordance for sighted/mouse users.

ActionableNotification has role="alertdialog" and takes focus and can be configured to be inline or toast visually.

mbgower commented 7 months ago

It's not so much a screen reader issue as it is a keyboard issue. A sighted mouse user can dismiss the notification. A sighted keyboard user cannot. That is an admittedly low-level failure of 2.1.1 Keyboard for the inline version, where there's not really any need to dismiss. But it begs the question why a mouse user can. It's demonstrably inequitable.

The bigger potential issue happens with the Toast version of the notification when it obscures content underneath it. That is a possible failure of Focus Not Obscured.

There are a few solutions to this, including providing timed display of Toaster, after which it is 'dismissed' and gets added to a list of notifications, which themselves are reviewable and able to be cleared by the user.

justindm234 commented 7 months ago

The testers for my application (IBM Z Hardware Management Console) just hit this. I believe the toast notification should have role ="alertdialog" when it is dismissable. If not, its close support should be removed to require devs to use the accessible ActionableNotification (which should then also support a caption prop)

tay1orjones commented 6 months ago

Initially, to make this equitable, we had closeOnEscape as an option for both ToastNotification and InlineNotification but we removed it in https://github.com/carbon-design-system/carbon/pull/11022. My recollection is that it was the determination of the Carbon Accessibility Guild after quite a bit of discussion. Unfortunately I can't remember the context and can't find any notes on it. This would've still presented issues for iOS voiceover users who don't have an escape key.

We should review together the additional solutions for Focus Not Obscured. ToastNotification already supports time-based dismissal via the timeout prop.

I don't think we could remove the close button from ToastNotification and InlineNotification without a breaking change. If we remove the ability to dismiss these manually, we would need to require a timeout and provide a default for it. Conversely, if we add the ability for a keyboard user to more easily close it, we're violating the spec of these roles to not take focus.

An adjacent issue here is that user interaction is required with ActionableNotification with role="alertdialog" because it traps focus. Requiring anyone who wants "dismissability" to use ActionableNotification could present a lot of issues within product/consumer usage.