[@angular-eslint/template/interactive-supports-focus] Forms are erroneously marked as unfocusable
Description and reproduction of the issue
The rule erroneously marks the following form element as "Elements with interaction handlers must be focusable."
<form (ngSubmit)="submit()" (keydown.control.enter)="submit()">
...
This is wrong because the handler is perfectly useful for submitting the form when focus is in any of its controls. The form itself is not required to have a tabindex, and it isn't meant to ever be focused itself.
In my opinion, this rule should check not only the element containing the handler, but all child elements as well, and defer if any of those is focusable. Keyboard events are bubbling by default:
Keyboard events are only generated by
<input>,<textarea>,<summary>and anything with thecontentEditableortabindexattribute. If not caught, they bubble up the DOM tree until they reach Document.
Versions
| package | version |
|---|---|
@angular-eslint/eslint-plugin-template |
16.0.3 |
@angular-eslint/template-parser |
16.0.3 |
@typescript-eslint/parser |
5.60.0 |
ESLint |
8.43.0 |
node |
18.16.0 |
# Please run `npx ng version` in your project and paste the full output here:
Angular CLI: 16.1.0
Node: 18.16.0
Package Manager: npm 9.5.1
OS: linux x64
Angular: 16.1.2
... animations, common, compiler, core, forms, localize
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1601.1
@angular-devkit/build-angular 16.1.1
@angular-devkit/core 16.1.0
@angular-devkit/schematics 16.1.0
@angular/cli 16.1.0
@angular/compiler-cli 16.1.0
@schematics/angular 16.1.0
rxjs 7.8.1
- [x] I have tried restarting my IDE and the issue persists.
- [x] I have updated to the latest supported version of the packages and checked my
ng versionoutput per the instructions given here.
I am getting the same issue with the following:
<mat-toolbar>
<div class="footer-left">
<span>...</span>
</div>
<div class="footer-center">
<span>...</span>
</div>
<div class="footer-right">
<span class="ui-icon ui-info" (click)="onClickInfo()" title="About..."></span> <!-- HERE -->
</div>
</mat-toolbar>
In addition to the examples listed, this can also apply to any place where the event listeners are listening for the events to bubble up. The individual items that can be clicked should be focusable, but the element that is listening to the bubbled events does not need to be in order for the functionality to be accessible.
Edit to add: This might not work in all situations, but just wanted to note for others that might find this, in looking at the rule page, there are a few ways to silence this error by indicating that the element does not need to be interactive to be accessible, despite the event. Depending on the use case, giving the element a role that doesn't require interactivity (i.e. presentation / none), marking the element as aria-hidden, aria-disabled, disabled, etc. are some of the potential options that allow this rule to pass. Obviously don't do any of these just to eliminate the error if it actually harms accessibility, but check the rule documentation for the full list of what markup will pass this rule.
Just end up with same errors with that rule - and it does not even go away if the div has tabindex=0 or role="button" I am forced to add aria-disabled="true"... but it is not disabled - it is a clickable div based element.
div based buttons and other intractable elements are extremely common in web and found across all UX libraries.
Same for < img >
@pedroll can I ask why you have click or keyboard events on an img? It’s not the sort of element where you’d be capturing bubbled events. Should you be wrapping the img in a button for accessibility?