Describe the bug
The dsBtnDisabled directive (BtnDisabledDirective) is designed to visually disable a button while maintaining its presence in the DOM for screen readers (using aria-disabled="true" instead of the native HTML disabled attribute). The directive correctly stops mouse clicks, but it fails to block the Space key due to an incorrect key value check in the HostListener.
Because of this, any button relying purely on [dsBtnDisabled] (without the native HTML disabled attribute or a Typescript safeguard) can still be triggered by keyboard-only users pressing the Space bar, which could result in unexpected backend requests or errors.
Note: In many existing components across the project (like forms), this bug is currently "silenced" because the component's TypeScript method has its own internal validation check (e.g., if (form.invalid) return;). However, if a button relies solely on the [dsBtnDisabled] directive to block interactions (as seen in PR #5395), the Space bar bypasses the directive and successfully triggers the component's action.
To Reproduce
Steps to reproduce the behavior (using PR #5395 as the scenario):
- Navigate to the "Edit Item" -> "Upload" section of an item and reduce it to a single bitstream. The delete button will become visually disabled via [dsBtnDisabled].
- Using the keyboard, press Tab until the focus is on the visually disabled delete button and press the Space bar.
- Behavior: The action is triggered. It attempts to delete the last bitstream, resulting in a 422 Unprocessable Entity error that breaks the UI.
Note: The test spec (disabled-directive.spec.ts) currently passes because it mocks the event with { key: 'Space' }, which masks the real browser behavior.
Expected behavior
When a button uses [dsBtnDisabled], pressing the Space bar should be intercepted and blocked (event.preventDefault() and event.stopImmediatePropagation()), exactly as it works for mouse clicks and the Enter key.
Technical Details & Proposed Fix
In src/app/shared/btn-disabled.directive.ts, the keydown listener checks for the literal string "Space":
|
if (this.isDisabled && (event.key === 'Enter' || event.key === 'Space')) { |
However, standard web browsers return a single space character (" ") for the KeyboardEvent.key property when the space bar is pressed, not the word "Space".
The fix is simply updating the condition to:
if (this.isDisabled && (event.key === 'Enter' || event.key === ' ')) {
And updating the mock event in disabled-directive.spec.ts to { key: ' ' }.
Related work
I discovered this bug while doing accessibility tests during the review of PR #5395.
I plan to submit a Pull Request to fix this directive and its related tests shortly.
Describe the bug
The
dsBtnDisableddirective (BtnDisabledDirective) is designed to visually disable a button while maintaining its presence in the DOM for screen readers (usingaria-disabled="true"instead of the native HTMLdisabledattribute). The directive correctly stops mouse clicks, but it fails to block theSpacekey due to an incorrect key value check in theHostListener.Because of this, any button relying purely on
[dsBtnDisabled](without the native HTMLdisabledattribute or a Typescript safeguard) can still be triggered by keyboard-only users pressing the Space bar, which could result in unexpected backend requests or errors.Note: In many existing components across the project (like forms), this bug is currently "silenced" because the component's TypeScript method has its own internal validation check (e.g., if (form.invalid) return;). However, if a button relies solely on the [dsBtnDisabled] directive to block interactions (as seen in PR #5395), the Space bar bypasses the directive and successfully triggers the component's action.
To Reproduce
Steps to reproduce the behavior (using PR #5395 as the scenario):
Note: The test spec (
disabled-directive.spec.ts) currently passes because it mocks the event with{ key: 'Space' }, which masks the real browser behavior.Expected behavior
When a button uses
[dsBtnDisabled], pressing theSpacebar should be intercepted and blocked (event.preventDefault()andevent.stopImmediatePropagation()), exactly as it works for mouse clicks and theEnterkey.Technical Details & Proposed Fix
In
src/app/shared/btn-disabled.directive.ts, thekeydownlistener checks for the literal string"Space":dspace-angular/src/app/shared/btn-disabled.directive.ts
Line 56 in feeb6ad
However, standard web browsers return a single space character (" ") for the KeyboardEvent.key property when the space bar is pressed, not the word "Space".
The fix is simply updating the condition to:
if (this.isDisabled && (event.key === 'Enter' || event.key === ' ')) {And updating the mock event in disabled-directive.spec.ts to { key: ' ' }.
Related work
I discovered this bug while doing accessibility tests during the review of PR #5395.
I plan to submit a Pull Request to fix this directive and its related tests shortly.