feat: add a11y `no-noninteractive-element-to-interactive-role` (#8167)

Part of #820
pull/8382/head
Nguyen Tran 2 years ago committed by GitHub
parent 127b61a465
commit 26c38e750c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -277,6 +277,17 @@ Some HTML elements have default ARIA roles. Giving these elements an ARIA role t
--- ---
### `a11y-no-noninteractive-element-to-interactive-role`
[WAI-ARIA](https://www.w3.org/TR/wai-aria-1.1/#usage_intro) roles should not be used to convert a non-interactive element to an interactive element. Interactive ARIA roles include `button`, `link`, `checkbox`, `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `radio`, `searchbox`, `switch` and `textbox`.
```sv
<!-- A11y: Non-interactive element <h3> cannot have interactive role 'searchbox' -->
<h3 role="searchbox">Button</h3>
```
---
### `a11y-no-noninteractive-tabindex` ### `a11y-no-noninteractive-tabindex`
Tab key navigation should be limited to elements on the page that can be interacted with. Tab key navigation should be limited to elements on the page that can be interacted with.

@ -119,6 +119,10 @@ export default {
code: 'a11y-no-interactive-element-to-noninteractive-role', code: 'a11y-no-interactive-element-to-noninteractive-role',
message: `A11y: <${element}> cannot have role '${role}'` message: `A11y: <${element}> cannot have role '${role}'`
}), }),
a11y_no_noninteractive_element_to_interactive_role: (role: string | boolean, element: string) => ({
code: 'a11y-no-noninteractive-element-to-interactive-role',
message: `A11y: Non-interactive element <${element}> cannot have interactive role '${role}'`
}),
a11y_role_has_required_aria_props: (role: string, props: string[]) => ({ a11y_role_has_required_aria_props: (role: string, props: string[]) => ({
code: 'a11y-role-has-required-aria-props', code: 'a11y-role-has-required-aria-props',
message: `A11y: Elements with the ARIA role "${role}" must have the following attributes defined: ${props.map(name => `"${name}"`).join(', ')}` message: `A11y: Elements with the ARIA role "${role}" must have the following attributes defined: ${props.map(name => `"${name}"`).join(', ')}`

@ -24,14 +24,13 @@ import { Literal } from 'estree';
import compiler_warnings from '../compiler_warnings'; import compiler_warnings from '../compiler_warnings';
import compiler_errors from '../compiler_errors'; import compiler_errors from '../compiler_errors';
import { ARIARoleDefinitionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query'; import { ARIARoleDefinitionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query';
import { is_interactive_element, is_non_interactive_roles, is_presentation_role, is_interactive_roles, is_hidden_from_screen_reader, is_semantic_role_element } from '../utils/a11y'; import { is_interactive_element, is_non_interactive_element, is_non_interactive_roles, is_presentation_role, is_interactive_roles, is_hidden_from_screen_reader, is_semantic_role_element, is_abstract_role } from '../utils/a11y';
const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' '); const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
const aria_attribute_set = new Set(aria_attributes); const aria_attribute_set = new Set(aria_attributes);
const aria_roles = roles.keys(); const aria_roles = roles.keys();
const aria_role_set = new Set(aria_roles); const aria_role_set = new Set(aria_roles);
const aria_role_abstract_set = new Set(roles.keys().filter(role => roles.get(role).abstract));
const a11y_required_attributes = { const a11y_required_attributes = {
a: ['href'], a: ['href'],
@ -567,7 +566,7 @@ export default class Element extends Node {
if (typeof value === 'string') { if (typeof value === 'string') {
value.split(regex_any_repeated_whitespaces).forEach((current_role: ARIARoleDefinitionKey) => { value.split(regex_any_repeated_whitespaces).forEach((current_role: ARIARoleDefinitionKey) => {
if (current_role && aria_role_abstract_set.has(current_role)) { if (current_role && is_abstract_role(current_role)) {
component.warn(attribute, compiler_warnings.a11y_no_abstract_role(current_role)); component.warn(attribute, compiler_warnings.a11y_no_abstract_role(current_role));
} else if (current_role && !aria_role_set.has(current_role)) { } else if (current_role && !aria_role_set.has(current_role)) {
const match = fuzzymatch(current_role, aria_roles); const match = fuzzymatch(current_role, aria_roles);
@ -607,8 +606,12 @@ export default class Element extends Node {
if (is_interactive_element(this.name, attribute_map) && (is_non_interactive_roles(current_role) || is_presentation_role(current_role))) { if (is_interactive_element(this.name, attribute_map) && (is_non_interactive_roles(current_role) || is_presentation_role(current_role))) {
component.warn(this, compiler_warnings.a11y_no_interactive_element_to_noninteractive_role(current_role, this.name)); component.warn(this, compiler_warnings.a11y_no_interactive_element_to_noninteractive_role(current_role, this.name));
} }
});
// no-noninteractive-element-to-interactive-role
if (is_non_interactive_element(this.name, attribute_map) && is_interactive_roles(current_role)) {
component.warn(this, compiler_warnings.a11y_no_noninteractive_element_to_interactive_role(current_role, this.name));
}
});
} }
} }

@ -7,7 +7,9 @@ import {
import { AXObjects, AXObjectRoles, elementAXObjects } from 'axobject-query'; import { AXObjects, AXObjectRoles, elementAXObjects } from 'axobject-query';
import Attribute from '../nodes/Attribute'; import Attribute from '../nodes/Attribute';
const non_abstract_roles = [...roles_map.keys()].filter((name) => !roles_map.get(name).abstract); const aria_roles = roles_map.keys();
const abstract_roles = new Set(aria_roles.filter(role => roles_map.get(role).abstract));
const non_abstract_roles = aria_roles.filter((name) => !abstract_roles.has(name));
const non_interactive_roles = new Set( const non_interactive_roles = new Set(
non_abstract_roles non_abstract_roles
@ -40,6 +42,10 @@ export function is_interactive_roles(role: ARIARoleDefinitionKey) {
return interactive_roles.has(role); return interactive_roles.has(role);
} }
export function is_abstract_role(role: ARIARoleDefinitionKey) {
return abstract_roles.has(role);
}
const presentation_roles = new Set(['presentation', 'none']); const presentation_roles = new Set(['presentation', 'none']);
export function is_presentation_role(role: ARIARoleDefinitionKey) { export function is_presentation_role(role: ARIARoleDefinitionKey) {
@ -65,7 +71,7 @@ export function is_hidden_from_screen_reader(tag_name: string, attribute_map: Ma
const non_interactive_element_role_schemas: ARIARoleRelationConcept[] = []; const non_interactive_element_role_schemas: ARIARoleRelationConcept[] = [];
elementRoles.entries().forEach(([schema, roles]) => { elementRoles.entries().forEach(([schema, roles]) => {
if ([...roles].every((role) => non_interactive_roles.has(role))) { if ([...roles].every((role) => role !== 'generic' && non_interactive_roles.has(role))) {
non_interactive_element_role_schemas.push(schema); non_interactive_element_role_schemas.push(schema);
} }
}); });
@ -82,6 +88,10 @@ const interactive_ax_objects = new Set(
[...AXObjects.keys()].filter((name) => AXObjects.get(name).type === 'widget') [...AXObjects.keys()].filter((name) => AXObjects.get(name).type === 'widget')
); );
const non_interactive_ax_objects = new Set(
[...AXObjects.keys()].filter((name) => ['windows', 'structure'].includes(AXObjects.get(name).type))
);
const interactive_element_ax_object_schemas: ARIARoleRelationConcept[] = []; const interactive_element_ax_object_schemas: ARIARoleRelationConcept[] = [];
elementAXObjects.entries().forEach(([schema, ax_object]) => { elementAXObjects.entries().forEach(([schema, ax_object]) => {
@ -90,6 +100,14 @@ elementAXObjects.entries().forEach(([schema, ax_object]) => {
} }
}); });
const non_interactive_element_ax_object_schemas: ARIARoleRelationConcept[] = [];
elementAXObjects.entries().forEach(([schema, ax_object]) => {
if ([...ax_object].every((role) => non_interactive_ax_objects.has(role))) {
non_interactive_element_ax_object_schemas.push(schema);
}
});
function match_schema( function match_schema(
schema: ARIARoleRelationConcept, schema: ARIARoleRelationConcept,
tag_name: string, tag_name: string,
@ -110,24 +128,31 @@ function match_schema(
}); });
} }
export function is_interactive_element( export enum ElementInteractivity {
Interactive = 'interactive',
NonInteractive = 'non-interactive',
Static = 'static',
}
export function element_interactivity(
tag_name: string, tag_name: string,
attribute_map: Map<string, Attribute> attribute_map: Map<string, Attribute>
): boolean { ): ElementInteractivity {
if ( if (
interactive_element_role_schemas.some((schema) => interactive_element_role_schemas.some((schema) =>
match_schema(schema, tag_name, attribute_map) match_schema(schema, tag_name, attribute_map)
) )
) { ) {
return true; return ElementInteractivity.Interactive;
} }
if ( if (
tag_name !== 'header' &&
non_interactive_element_role_schemas.some((schema) => non_interactive_element_role_schemas.some((schema) =>
match_schema(schema, tag_name, attribute_map) match_schema(schema, tag_name, attribute_map)
) )
) { ) {
return false; return ElementInteractivity.NonInteractive;
} }
if ( if (
@ -135,10 +160,30 @@ export function is_interactive_element(
match_schema(schema, tag_name, attribute_map) match_schema(schema, tag_name, attribute_map)
) )
) { ) {
return true; return ElementInteractivity.Interactive;
} }
return false; if (
non_interactive_element_ax_object_schemas.some((schema) =>
match_schema(schema, tag_name, attribute_map)
)
) {
return ElementInteractivity.NonInteractive;
}
return ElementInteractivity.Static;
}
export function is_interactive_element(tag_name: string, attribute_map: Map<string, Attribute>): boolean {
return element_interactivity(tag_name, attribute_map) === ElementInteractivity.Interactive;
}
export function is_non_interactive_element(tag_name: string, attribute_map: Map<string, Attribute>): boolean {
return element_interactivity(tag_name, attribute_map) === ElementInteractivity.NonInteractive;
}
export function is_static_element(tag_name: string, attribute_map: Map<string, Attribute>): boolean {
return element_interactivity(tag_name, attribute_map) === ElementInteractivity.Static;
} }
export function is_semantic_role_element(role: ARIARoleDefinitionKey, tag_name: string, attribute_map: Map<string, Attribute>) { export function is_semantic_role_element(role: ARIARoleDefinitionKey, tag_name: string, attribute_map: Map<string, Attribute>) {

@ -71,36 +71,34 @@
<div role="widget" /> <div role="widget" />
<div role="window" /> <div role="window" />
<!-- HTML elements with an inherent, non-interactive role, assigned an interactive role. --> <!-- VALID: div elements assigned an interactive role. -->
<main role="button" /> <div role="button" />
<area role="button" alt="x" /> <div role="checkbox" aria-checked={true} />
<article role="button" /> <div role="columnheader" />
<article role="button" /> <div role="combobox" aria-controls={[]} aria-expanded={true} />
<dd role="button" /> <div role="grid" />
<dfn role="button" /> <div role="gridcell" />
<dt role="button" /> <div role="link" />
<fieldset role="button" /> <div role="listbox" />
<figure role="button" /> <div role="menu" />
<form role="button" /> <div role="menubar" />
<frame role="button" /> <div role="menuitem" />
<h1 role="button">title</h1> <div role="menuitemcheckbox" aria-checked />
<h2 role="button">title</h2> <div role="menuitemradio" aria-checked />
<h3 role="button">title</h3> <div role="option" aria-selected />
<h4 role="button">title</h4> <div role="progressbar" />
<h5 role="button">title</h5> <div role="radio" aria-checked />
<h6 role="button">title</h6> <div role="radiogroup" />
<hr role="button" /> <div role="row" />
<img role="button" alt="x" /> <div role="rowheader" />
<li role="button" /> <div role="scrollbar" aria-controls={[]} aria-valuenow={0} />
<li role="presentation" /> <div role="searchbox" />
<nav role="button" /> <div role="slider" aria-valuenow={0} />
<ol role="button" /> <div role="spinbutton" />
<table role="button" /> <div role="switch" aria-checked />
<tbody role="button" /> <div role="tab" />
<td role="button" /> <div role="textbox" />
<tfoot role="button" /> <div role="treeitem" aria-selected={true} />
<thead role="button" />
<ul role="button" />
<!-- HTML elements attributed with a non-interactive role --> <!-- HTML elements attributed with a non-interactive role -->
<div role="alert" /> <div role="alert" />

@ -639,72 +639,72 @@
"code": "a11y-no-interactive-element-to-noninteractive-role", "code": "a11y-no-interactive-element-to-noninteractive-role",
"end": { "end": {
"column": 28, "column": 28,
"line": 145 "line": 143
}, },
"message": "A11y: <menuitem> cannot have role 'listitem'", "message": "A11y: <menuitem> cannot have role 'listitem'",
"start": { "start": {
"column": 0, "column": 0,
"line": 145 "line": 143
} }
}, },
{ {
"code": "a11y-no-interactive-element-to-noninteractive-role", "code": "a11y-no-interactive-element-to-noninteractive-role",
"end": { "end": {
"column": 38, "column": 38,
"line": 146 "line": 144
}, },
"message": "A11y: <option> cannot have role 'listitem'", "message": "A11y: <option> cannot have role 'listitem'",
"start": { "start": {
"column": 0, "column": 0,
"line": 146 "line": 144
} }
}, },
{ {
"code": "a11y-no-interactive-element-to-noninteractive-role", "code": "a11y-no-interactive-element-to-noninteractive-role",
"end": { "end": {
"column": 38, "column": 38,
"line": 147 "line": 145
}, },
"message": "A11y: <select> cannot have role 'listitem'", "message": "A11y: <select> cannot have role 'listitem'",
"start": { "start": {
"column": 0, "column": 0,
"line": 147 "line": 145
} }
}, },
{ {
"code": "a11y-no-interactive-element-to-noninteractive-role", "code": "a11y-no-interactive-element-to-noninteractive-role",
"end": { "end": {
"column": 27, "column": 27,
"line": 148 "line": 146
}, },
"message": "A11y: <summary> cannot have role 'listitem'", "message": "A11y: <summary> cannot have role 'listitem'",
"start": { "start": {
"column": 0, "column": 0,
"line": 148 "line": 146
} }
}, },
{ {
"code": "a11y-no-interactive-element-to-noninteractive-role", "code": "a11y-no-interactive-element-to-noninteractive-role",
"end": { "end": {
"column": 40, "column": 40,
"line": 149 "line": 147
}, },
"message": "A11y: <textarea> cannot have role 'listitem'", "message": "A11y: <textarea> cannot have role 'listitem'",
"start": { "start": {
"column": 0, "column": 0,
"line": 149 "line": 147
} }
}, },
{ {
"code": "a11y-no-interactive-element-to-noninteractive-role", "code": "a11y-no-interactive-element-to-noninteractive-role",
"end": { "end": {
"column": 22, "column": 22,
"line": 150 "line": 148
}, },
"message": "A11y: <tr> cannot have role 'listitem'", "message": "A11y: <tr> cannot have role 'listitem'",
"start": { "start": {
"column": 0, "column": 0,
"line": 150 "line": 148
} }
} }
] ]

@ -0,0 +1,109 @@
<!-- ALL INVALID: HTML elements with interactive role -->
<article role="button" />
<aside role="checkbox" aria-checked={false} />
<blockquote role="columnheader" />
<body role="combobox" aria-controls={[]} aria-expanded />
<br role="grid" />
<caption role="gridcell" />
<dd role="link" />
<details role="listbox" />
<dir role="menu" />
<dl role="menubar" />
<dfn role="menuitem" />
<dt role="menuitemcheckbox" aria-checked />
<fieldset role="menuitemradio" aria-checked />
<figure>
<figcaption role="menuitemradio" aria-checked />
</figure>
<figure role="option" aria-selected />
<footer role="radio" aria-checked />
<form role="radiogroup" />
<frame role="row" />
<h1 role="rowheader">Button</h1>
<h2 role="scrollbar" aria-controls={[]} aria-valuenow={0} >Button</h2>
<h3 role="searchbox">Button</h3>
<h4 role="slider" aria-valuenow={0}>Button</h4>
<h5 role="spinbutton">Button</h5>
<h6 role="switch" aria-checked>Button</h6>
<hr role="tab" />
<img role="tabpanel" alt="tabpanel" />
<label role="textbox" />
<legend role="toolbar" />
<li role="tree" />
<main role="treegrid" />
<mark role="treeitem" aria-selected />
<marquee role="doc-backlink" />
<menu role="doc-biblioref" />
<meter role="doc-glossref" />
<nav role="doc-noteref" />
<ol role="button" />
<optgroup role="treeitem" aria-selected />
<output role="treegrid" />
<p role="columnheader" />
<pre role="tree" />
<progress role="combobox" aria-controls={[]} aria-expanded />
<ruby role="toolbar" />
<section role="radio" aria-label="radio" aria-checked />
<table role="menu" />
<tbody role="searchbox" />
<td role="button" />
<tfoot role="listbox" />
<thead role="slider" aria-valuenow={0} />
<time role="doc-backlink" />
<ul role="spinbutton" />
<!-- VALID under recommended settings, INVALID under strict settings: ul, ol, li has interactive roles -->
<!-- ul -->
<ul role="menu" />
<ul role="menubar" />
<ul role="radiogroup" />
<ul role="tablist" />
<ul role="tree" />
<ul role="treegrid" />
<!-- ol -->
<ol role="menu" />
<ol role="menubar" />
<ol role="radiogroup" />
<ol role="tablist" />
<ol role="tree" />
<ol role="treegrid" />
<!-- li -->
<li role="tab" />
<li role="menuitem" />
<li role="row" />
<li role="treeitem" aria-selected={false} />
<!-- VALID: div elements assigned an interactive role. -->
<div role="button" />
<div role="checkbox" aria-checked={true} />
<div role="columnheader" />
<div role="combobox" aria-controls={[]} aria-expanded={true} />
<div role="grid" />
<div role="gridcell" />
<div role="link" />
<div role="listbox" />
<div role="menu" />
<div role="menubar" />
<div role="menuitem" />
<div role="menuitemcheckbox" aria-checked />
<div role="menuitemradio" aria-checked />
<div role="option" aria-selected />
<div role="progressbar" />
<div role="radio" aria-checked />
<div role="radiogroup" />
<div role="row" />
<div role="rowheader" />
<div role="scrollbar" aria-controls={[]} aria-valuenow={0} />
<div role="searchbox" />
<div role="slider" aria-valuenow={0} />
<div role="spinbutton" />
<div role="switch" aria-checked />
<div role="tab" />
<div role="textbox" />
<div role="treeitem" aria-selected={true} />
<!-- VALID: HTML elements attributed with a non-interactive role -->
<div role="alert" />
<div role="document" />
<div role="separator" />
<div role="timer" />

@ -0,0 +1,818 @@
[
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 25,
"line": 2
},
"message": "A11y: Non-interactive element <article> cannot have interactive role 'button'",
"start": {
"column": 0,
"line": 2
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 46,
"line": 3
},
"message": "A11y: Non-interactive element <aside> cannot have interactive role 'checkbox'",
"start": {
"column": 0,
"line": 3
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 34,
"line": 4
},
"message": "A11y: Non-interactive element <blockquote> cannot have interactive role 'columnheader'",
"start": {
"column": 0,
"line": 4
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 57,
"line": 5
},
"message": "A11y: Non-interactive element <body> cannot have interactive role 'combobox'",
"start": {
"column": 0,
"line": 5
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 18,
"line": 6
},
"message": "A11y: Non-interactive element <br> cannot have interactive role 'grid'",
"start": {
"column": 0,
"line": 6
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 27,
"line": 7
},
"message": "A11y: Non-interactive element <caption> cannot have interactive role 'gridcell'",
"start": {
"column": 0,
"line": 7
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 18,
"line": 8
},
"message": "A11y: Non-interactive element <dd> cannot have interactive role 'link'",
"start": {
"column": 0,
"line": 8
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 26,
"line": 9
},
"message": "A11y: Non-interactive element <details> cannot have interactive role 'listbox'",
"start": {
"column": 0,
"line": 9
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 19,
"line": 10
},
"message": "A11y: Non-interactive element <dir> cannot have interactive role 'menu'",
"start": {
"column": 0,
"line": 10
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 21,
"line": 11
},
"message": "A11y: Non-interactive element <dl> cannot have interactive role 'menubar'",
"start": {
"column": 0,
"line": 11
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 23,
"line": 12
},
"message": "A11y: Non-interactive element <dfn> cannot have interactive role 'menuitem'",
"start": {
"column": 0,
"line": 12
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 43,
"line": 13
},
"message": "A11y: Non-interactive element <dt> cannot have interactive role 'menuitemcheckbox'",
"start": {
"column": 0,
"line": 13
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 46,
"line": 14
},
"message": "A11y: Non-interactive element <fieldset> cannot have interactive role 'menuitemradio'",
"start": {
"column": 0,
"line": 14
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 50,
"line": 16
},
"message": "A11y: Non-interactive element <figcaption> cannot have interactive role 'menuitemradio'",
"start": {
"column": 2,
"line": 16
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 38,
"line": 18
},
"message": "A11y: Non-interactive element <figure> cannot have interactive role 'option'",
"start": {
"column": 0,
"line": 18
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 36,
"line": 19
},
"message": "A11y: Non-interactive element <footer> cannot have interactive role 'radio'",
"start": {
"column": 0,
"line": 19
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 26,
"line": 20
},
"message": "A11y: Non-interactive element <form> cannot have interactive role 'radiogroup'",
"start": {
"column": 0,
"line": 20
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 20,
"line": 21
},
"message": "A11y: Non-interactive element <frame> cannot have interactive role 'row'",
"start": {
"column": 0,
"line": 21
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 32,
"line": 22
},
"message": "A11y: Non-interactive element <h1> cannot have interactive role 'rowheader'",
"start": {
"column": 0,
"line": 22
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 70,
"line": 23
},
"message": "A11y: Non-interactive element <h2> cannot have interactive role 'scrollbar'",
"start": {
"column": 0,
"line": 23
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 32,
"line": 24
},
"message": "A11y: Non-interactive element <h3> cannot have interactive role 'searchbox'",
"start": {
"column": 0,
"line": 24
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 47,
"line": 25
},
"message": "A11y: Non-interactive element <h4> cannot have interactive role 'slider'",
"start": {
"column": 0,
"line": 25
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 33,
"line": 26
},
"message": "A11y: Non-interactive element <h5> cannot have interactive role 'spinbutton'",
"start": {
"column": 0,
"line": 26
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 42,
"line": 27
},
"message": "A11y: Non-interactive element <h6> cannot have interactive role 'switch'",
"start": {
"column": 0,
"line": 27
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 17,
"line": 28
},
"message": "A11y: Non-interactive element <hr> cannot have interactive role 'tab'",
"start": {
"column": 0,
"line": 28
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 38,
"line": 29
},
"message": "A11y: Non-interactive element <img> cannot have interactive role 'tabpanel'",
"start": {
"column": 0,
"line": 29
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 24,
"line": 30
},
"message": "A11y: Non-interactive element <label> cannot have interactive role 'textbox'",
"start": {
"column": 0,
"line": 30
}
},
{
"code": "a11y-label-has-associated-control",
"end": {
"column": 24,
"line": 30
},
"message": "A11y: A form label must be associated with a control.",
"start": {
"column": 0,
"line": 30
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 25,
"line": 31
},
"message": "A11y: Non-interactive element <legend> cannot have interactive role 'toolbar'",
"start": {
"column": 0,
"line": 31
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 18,
"line": 32
},
"message": "A11y: Non-interactive element <li> cannot have interactive role 'tree'",
"start": {
"column": 0,
"line": 32
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 24,
"line": 33
},
"message": "A11y: Non-interactive element <main> cannot have interactive role 'treegrid'",
"start": {
"column": 0,
"line": 33
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 38,
"line": 34
},
"message": "A11y: Non-interactive element <mark> cannot have interactive role 'treeitem'",
"start": {
"column": 0,
"line": 34
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 31,
"line": 35
},
"message": "A11y: Non-interactive element <marquee> cannot have interactive role 'doc-backlink'",
"start": {
"column": 0,
"line": 35
}
},
{
"code": "a11y-distracting-elements",
"end": {
"column": 31,
"line": 35
},
"message": "A11y: Avoid <marquee> elements",
"start": {
"column": 0,
"line": 35
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 29,
"line": 36
},
"message": "A11y: Non-interactive element <menu> cannot have interactive role 'doc-biblioref'",
"start": {
"column": 0,
"line": 36
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 29,
"line": 37
},
"message": "A11y: Non-interactive element <meter> cannot have interactive role 'doc-glossref'",
"start": {
"column": 0,
"line": 37
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 26,
"line": 38
},
"message": "A11y: Non-interactive element <nav> cannot have interactive role 'doc-noteref'",
"start": {
"column": 0,
"line": 38
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 20,
"line": 39
},
"message": "A11y: Non-interactive element <ol> cannot have interactive role 'button'",
"start": {
"column": 0,
"line": 39
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 42,
"line": 40
},
"message": "A11y: Non-interactive element <optgroup> cannot have interactive role 'treeitem'",
"start": {
"column": 0,
"line": 40
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 26,
"line": 41
},
"message": "A11y: Non-interactive element <output> cannot have interactive role 'treegrid'",
"start": {
"column": 0,
"line": 41
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 25,
"line": 42
},
"message": "A11y: Non-interactive element <p> cannot have interactive role 'columnheader'",
"start": {
"column": 0,
"line": 42
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 19,
"line": 43
},
"message": "A11y: Non-interactive element <pre> cannot have interactive role 'tree'",
"start": {
"column": 0,
"line": 43
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 61,
"line": 44
},
"message": "A11y: Non-interactive element <progress> cannot have interactive role 'combobox'",
"start": {
"column": 0,
"line": 44
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 23,
"line": 45
},
"message": "A11y: Non-interactive element <ruby> cannot have interactive role 'toolbar'",
"start": {
"column": 0,
"line": 45
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 56,
"line": 46
},
"message": "A11y: Non-interactive element <section> cannot have interactive role 'radio'",
"start": {
"column": 0,
"line": 46
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 21,
"line": 47
},
"message": "A11y: Non-interactive element <table> cannot have interactive role 'menu'",
"start": {
"column": 0,
"line": 47
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 26,
"line": 48
},
"message": "A11y: Non-interactive element <tbody> cannot have interactive role 'searchbox'",
"start": {
"column": 0,
"line": 48
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 20,
"line": 49
},
"message": "A11y: Non-interactive element <td> cannot have interactive role 'button'",
"start": {
"column": 0,
"line": 49
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 24,
"line": 50
},
"message": "A11y: Non-interactive element <tfoot> cannot have interactive role 'listbox'",
"start": {
"column": 0,
"line": 50
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 41,
"line": 51
},
"message": "A11y: Non-interactive element <thead> cannot have interactive role 'slider'",
"start": {
"column": 0,
"line": 51
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 28,
"line": 52
},
"message": "A11y: Non-interactive element <time> cannot have interactive role 'doc-backlink'",
"start": {
"column": 0,
"line": 52
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 24,
"line": 53
},
"message": "A11y: Non-interactive element <ul> cannot have interactive role 'spinbutton'",
"start": {
"column": 0,
"line": 53
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 18,
"line": 57
},
"message": "A11y: Non-interactive element <ul> cannot have interactive role 'menu'",
"start": {
"column": 0,
"line": 57
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 21,
"line": 58
},
"message": "A11y: Non-interactive element <ul> cannot have interactive role 'menubar'",
"start": {
"column": 0,
"line": 58
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 24,
"line": 59
},
"message": "A11y: Non-interactive element <ul> cannot have interactive role 'radiogroup'",
"start": {
"column": 0,
"line": 59
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 21,
"line": 60
},
"message": "A11y: Non-interactive element <ul> cannot have interactive role 'tablist'",
"start": {
"column": 0,
"line": 60
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 18,
"line": 61
},
"message": "A11y: Non-interactive element <ul> cannot have interactive role 'tree'",
"start": {
"column": 0,
"line": 61
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 22,
"line": 62
},
"message": "A11y: Non-interactive element <ul> cannot have interactive role 'treegrid'",
"start": {
"column": 0,
"line": 62
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 18,
"line": 64
},
"message": "A11y: Non-interactive element <ol> cannot have interactive role 'menu'",
"start": {
"column": 0,
"line": 64
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 21,
"line": 65
},
"message": "A11y: Non-interactive element <ol> cannot have interactive role 'menubar'",
"start": {
"column": 0,
"line": 65
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 24,
"line": 66
},
"message": "A11y: Non-interactive element <ol> cannot have interactive role 'radiogroup'",
"start": {
"column": 0,
"line": 66
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 21,
"line": 67
},
"message": "A11y: Non-interactive element <ol> cannot have interactive role 'tablist'",
"start": {
"column": 0,
"line": 67
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 18,
"line": 68
},
"message": "A11y: Non-interactive element <ol> cannot have interactive role 'tree'",
"start": {
"column": 0,
"line": 68
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 22,
"line": 69
},
"message": "A11y: Non-interactive element <ol> cannot have interactive role 'treegrid'",
"start": {
"column": 0,
"line": 69
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 17,
"line": 71
},
"message": "A11y: Non-interactive element <li> cannot have interactive role 'tab'",
"start": {
"column": 0,
"line": 71
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 22,
"line": 72
},
"message": "A11y: Non-interactive element <li> cannot have interactive role 'menuitem'",
"start": {
"column": 0,
"line": 72
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 17,
"line": 73
},
"message": "A11y: Non-interactive element <li> cannot have interactive role 'row'",
"start": {
"column": 0,
"line": 73
}
},
{
"code": "a11y-no-noninteractive-element-to-interactive-role",
"end": {
"column": 44,
"line": 74
},
"message": "A11y: Non-interactive element <li> cannot have interactive role 'treeitem'",
"start": {
"column": 0,
"line": 74
}
}
]
Loading…
Cancel
Save