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

Accessibility: Bootstrap must not remove outline on focusable disabled buttons #40564

Closed
3 tasks done
rr-it opened this issue Jun 16, 2024 · 11 comments
Closed
3 tasks done
Assignees

Comments

@rr-it
Copy link

rr-it commented Jun 16, 2024

Prerequisites

Describe the issue

A disabled button that is still focusable by keyboard must show on focus that it has the current focus.
Otherwise a user does not see where the current focus is.

Here the outline gets removed:

bootstrap/scss/_reboot.scss

Lines 395 to 402 in d2d4581

// Explicitly remove focus outline in Chromium when it shouldn't be
// visible (e.g. as result of mouse click or touch tap). It already
// should be doing this automatically, but seems to currently be
// confused and applies its very visible two-tone outline anyway.
button:focus:not(:focus-visible) {
outline: 0;
}

There is a special HTML attribute to explicitly state the intend to make a button disabled and keep the button focusable at the same time:
aria-disabled="true"

See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled

When needing to disable native HTML form controls, developers will need to specify the disabled attribute, as it provides all of the generally expected features of disabling a control by default.

However, there can be instances where elements need to be exposed as disabled, but are still available for users to find when navigating via the Tab key. Doing so can improve their discoverability as they will not be removed from the focus order of the web page, as aria-disabled does not change the focusability of such elements, nor will the elements be dimmed by default browser styling, making them easier to read. Some examples of where this may be useful include:

  • The header button element associated with non-collapsible accordion panel,
  • A button which is important to keep in the page's focus order, but its action is presently unavailable - such as submitting a form,
  • Temporarily inactive items in a menu widget that would otherwise be skipped over via standard keyboard navigation.

Reduced test cases

This button below is intentional focusable by the use of the attribute aria-disabled="true":
Therefore the button must have a visible outline on focus.

<button class="disabled" aria-disabled="true">Label</button>

This button below is really disabled by the use of the attribute disabled="disabled":
If it becomes somehow focused, it might or might not have its outline visible.

<button class="disabled" disabled="disabled">Label</button>

What operating system(s) are you seeing the problem on?

Linux

What browser(s) are you seeing the problem on?

Firefox

What version of Bootstrap are you using?

v5.3.2

@rr-it
Copy link
Author

rr-it commented Jun 16, 2024

Related to #38903 , but the intention is not on accessibility there.

@patrickhlauke
Copy link
Member

a button with aria-disabled still has a focus outline, right now. is this some kind of speculative issue here? or are you actually experiencing a problem where you're adding aria-disabled and there is no focus outline?

@rr-it
Copy link
Author

rr-it commented Jun 17, 2024

Tried to reproduce with default Bootstrap Dropdown menu and I could not reproduce the outline issue:
https://codepen.io/rr-it/pen/zYQpmpL

I'll recheck the code where it actually fails.


Found another a11y issue:
aria-disabled should still be reachable by cursor-key-movement (Bootstrap JS implementation).

https://getbootstrap.com/docs/5.0/components/dropdowns/#accessibility

However, Bootstrap does add built-in support for most standard keyboard menu interactions, such as the ability to move through individual .dropdown-item elements using the cursor keys and close the menu with the ESC key.

Example https://codepen.io/rr-it/pen/zYQpmpL

  • Using Tab-key: aria-disabled list-item is reachable.
  • Using cursor-keys: aria-disabled list-item is not reachable.

Tab-key usage:

twbs-dropdown-aria-disabled-tab_key.webm

Arrow-key usage:

twbs-dropdown-aria-disabled-cursor_keys.webm

@patrickhlauke
Copy link
Member

the cursor behaviour is a nice-to-have addition, but if you are disabling a control with aria-disabled, i'm puzzled why you'd also still want to reach it with the cursor keys. what's your use case here?

@rr-it
Copy link
Author

rr-it commented Jun 17, 2024

So the original issue is not Bootstrap related. It was provoked by some custom CSS rule:

--typo3-list-item-disabled-border-color: transparent;

.dropdown-item.disabled, .dropdown-item:disabled {
  outline: 1px solid var(--typo3-list-item-disabled-border-color);
}

the cursor behaviour is a nice-to-have addition, but if you are disabling a control with aria-disabled, i'm puzzled why you'd also still want to reach it with the cursor keys. what's your use case here?

Use-case:

Dropdown menu wit a menu-entry to trigger action "set internal bookmark":

grafik

When the bookmark is already set, a special info is shown that the bookmark is already set:

grafik

  • This info that the bookmark is set should be read-out by screenreader.
    disabled="disabled" might suppress read-out.

  • This element should still be focusable while disabled so that the focus order does not change.
    A power-user might memorize the key-sequence on how to fastly trigger the second entry "Copy URL of this record":

Trigger sequence using [Tab]

[Tab], [Space], 2x [Tab], [Space]:

  1. [Tab]: focuses dropdown-button
  2. [Space]: opens dropdown
  3. [Tab]: focuses first entry 'set bookmark'
  4. [Tab]: focuses second entry 'copy url'
  5. [Space]: triggers action "Copy URL of this record"
    If the first entry 'set bookmark' is missing in focus order, this changes the number of neccessary [Tab] to reach second entry 'copy url'.

Trigger sequence using cursor-key [Down] - not working with first entry disabled:

[Tab], 2x cursor-key [Down], [Space]:

  1. [Tab]: focuses dropdown-button
  2. cursor-key [Down]: opens dropdown and focuses first entry 'set bookmark'
  3. cursor-key [Down]: focuses second entry 'copy url'
  4. [Space]: triggers action "Copy URL of this record"
    If the first entry 'set bookmark' is missing in focus order, this changes the number of neccessary cursor-key [Down] to reach second entry 'copy url'.

With first entry disabled this changes to:
[Tab], 1x cursor-key [Down], [Space]

Also see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled

However, there can be instances where elements need to be exposed as disabled, but are still available for users to find when navigating via the Tab key. Doing so can improve their discoverability as they will not be removed from the focus order of the web page, as aria-disabled does not change the focusability of such elements, […]:

  • Temporarily inactive items in a menu widget that would otherwise be skipped over via standard keyboard navigation.

@patrickhlauke
Copy link
Member

patrickhlauke commented Jun 17, 2024

This info that the bookmark is set should be read-out by screenreader. disabled="disabled" might suppress read-out.

Screen readers still read out buttons that are disabled. it just means that they won't be in the keyboard focus cycle.

This element should still be focusable while disabled so that the focus order does not change.

for what it's worth, at least on Windows, in regular application menus, disabled menu items don't receive focus - so it's not unusual

@rr-it
Copy link
Author

rr-it commented Jun 17, 2024

Screen readers still read out buttons that are disabled. it just means that they won't be in the keyboard focus cycle.

Orca (Screenreader for Gnome Desktop on Linux) has two modes

Orca + Firefox on Linux:

  • In 'focus mode' by navigating via [Tab] Orca follows focus sequence thereby skips and does not read out disabled buttons.
  • In 'browse mode' Orca is directed by cursor-keys and does focus and read out disabled buttons.

In 'browse mode' the cursor-keys are solely handled by orca - e.g. Bootstrap cursor-key [Down] does not trigger dropdown open.


Orca has some handy auto-mode-switching which is triggered on focusing the first item of a list:

  • Orca reads first item of list.
  • Orca announces number of elements in list - including disabled elements.
  • Orca auto-switches to 'browse mode' - thereby making it possible to reach disabled items by cursor-keys.

But if you don't wait for all these announcements to finish, e.g. by pressing [Tab]:

  • Orca won't activate 'browse mode' automatically.
  • You won't be able to reach disabled items.

I never waited - and thereby I did never reach the disabled items.

@rr-it
Copy link
Author

rr-it commented Jun 17, 2024

A new test-case: first element disabled

https://codepen.io/rr-it/pen/MWdrdrO

Result on dropdown-open via [Space] and jumping into list via [Tab]:

  • First entry <button disabled>: Focus goes directly to second entry. (Bad.)
  • First entry <button class="disabled" aria-disabled="true">: Focus goes to this first element. (Good.)

Result on combined dropdown-open with jumping into list by cursor-key [Down]:

  • First entry <button disabled>: Focus goes directly to second entry. (Bad.)
  • First entry <button class="disabled" aria-disabled="true">: Focus also goes directly to second entry. (Bad.)

On all examples above where the focus goes to the second element, screenreader Orca still announces the number of elements (e.g. 3) with all elements included, but no current position.
So the user might assume to be on the first element and all other elements are following below - whereas one element is actually above.

How do other screenreader software react in this case? Do they also focus the first non-disabled element?

@patrickhlauke
Copy link
Member

there is no issue here. activating button via Space (to expand the disclosure widget), then navigating with cursor keys, when screen reader is enabled, is the default way SR users will navigate (in browse mode). the additional cursor key navigation that BS adds on top of this dropdown/disclosure widget is an additional "nice to have" for keyboard (sighted, non-SR) users.

@rr-it
Copy link
Author

rr-it commented Jun 18, 2024

@patrickhlauke Thanks for your time for looking into this!

What I learned:

  • A dropdown menu that has its first entry disabled, might better have a first entry <button class="disabled" aria-disabled="true">. Thereby screenreader users don't skip the first entry on jumping into the list while in screenreader 'focus mode'.
  • Screenreader navigation uses cursor-keys while in 'browse mode' and does not rely on JS-implemented cursor-key-navigation.

@rr-it
Copy link
Author

rr-it commented Jun 21, 2024

@patrickhlauke You write:

the additional cursor key navigation that BS adds on top of this dropdown/disclosure widget is an additional "nice to have" for keyboard (sighted, non-SR) users.

The docs for 'Dropdowns' says:
https://getbootstrap.com/docs/5.3/components/dropdowns/#accessibility

Accessibility

[…]

However, Bootstrap does add built-in support for most standard keyboard menu interactions, such as the ability to move through individual .dropdown-item elements using the cursor keys and close the menu with the Esc key.

Here the docs should be changed, shouldn't they?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants