mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(linter): eslint-plugin-jsx-a11y role-has-required-aria-props (#1881)
partof: https://github.com/oxc-project/oxc/issues/1141 Based on: - doc: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/role-has-required-aria-props.md - code: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/rules/role-has-required-aria-props.js - test: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/__tests__/src/rules/role-has-required-aria-props-test.js
This commit is contained in:
parent
8a7efc2c3b
commit
2b7ca5962f
3 changed files with 409 additions and 0 deletions
|
|
@ -254,6 +254,7 @@ mod jsx_a11y {
|
|||
pub mod no_autofocus;
|
||||
pub mod no_distracting_elements;
|
||||
pub mod prefer_tag_over_role;
|
||||
pub mod role_has_required_aria_props;
|
||||
pub mod role_support_aria_props;
|
||||
pub mod scope;
|
||||
pub mod tab_index_no_positive;
|
||||
|
|
@ -509,6 +510,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
jsx_a11y::no_aria_hidden_on_focusable,
|
||||
jsx_a11y::no_autofocus,
|
||||
jsx_a11y::prefer_tag_over_role,
|
||||
jsx_a11y::role_has_required_aria_props,
|
||||
jsx_a11y::scope,
|
||||
jsx_a11y::tab_index_no_positive,
|
||||
jsx_a11y::aria_role,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
use crate::{context::LintContext, rule::Rule, utils::has_jsx_prop_lowercase, AstNode};
|
||||
use oxc_ast::{
|
||||
ast::{JSXAttributeItem, JSXAttributeValue},
|
||||
AstKind,
|
||||
};
|
||||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::{self, Error},
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
use phf::{phf_map, phf_set};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error(
|
||||
"eslint-plugin-jsx-a11y(role-has-required-aria-props): `{role}` role is missing required aria props `{props}`."
|
||||
)]
|
||||
#[diagnostic(
|
||||
severity(warning),
|
||||
help("Add missing aria props `{props}` to the element with `{role}` role.")
|
||||
)]
|
||||
struct RoleHasRequiredAriaPropsDiagnostic {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub role: String,
|
||||
pub props: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct RoleHasRequiredAriaProps;
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
/// Enforces that elements with ARIA roles must have all required attributes for that role.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Certain ARIA roles require specific attributes to express necessary semantics for assistive technology.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// // Bad
|
||||
/// <div role="checkbox" />
|
||||
///
|
||||
/// // Good
|
||||
/// <div role="checkbox" aria-checked="false" />
|
||||
/// ```
|
||||
RoleHasRequiredAriaProps,
|
||||
correctness
|
||||
);
|
||||
|
||||
static ROLE_TO_REQUIRED_ARIA_PROPS: phf::Map<&'static str, phf::Set<&'static str>> = phf_map! {
|
||||
"checkbox" => phf_set!{"aria-checked"},
|
||||
"radio" => phf_set!{"aria-checked"},
|
||||
"combobox" => phf_set!{"aria-controls", "aria-expanded"},
|
||||
"tab" => phf_set!{"aria-selected"},
|
||||
"slider" => phf_set!{"aria-valuemax", "aria-valuemin", "aria-valuenow"},
|
||||
"scrollbar" => phf_set!{"aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-orientation", "aria-controls"},
|
||||
"heading" => phf_set!{"aria-level"},
|
||||
"option" => phf_set!{"aria-selected"},
|
||||
};
|
||||
|
||||
impl Rule for RoleHasRequiredAriaProps {
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
if let AstKind::JSXOpeningElement(jsx_el) = node.kind() {
|
||||
let Some(role_prop) = has_jsx_prop_lowercase(jsx_el, "role") else { return };
|
||||
let JSXAttributeItem::Attribute(attr) = role_prop else { return };
|
||||
let Some(JSXAttributeValue::StringLiteral(role_values)) = &attr.value else { return };
|
||||
let roles = role_values.value.split_whitespace();
|
||||
for role in roles {
|
||||
if let Some(props) = ROLE_TO_REQUIRED_ARIA_PROPS.get(role) {
|
||||
for prop in props {
|
||||
if has_jsx_prop_lowercase(jsx_el, prop).is_none() {
|
||||
ctx.diagnostic(RoleHasRequiredAriaPropsDiagnostic {
|
||||
span: attr.span,
|
||||
role: role.into(),
|
||||
props: (*prop).into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::rules::RoleHasRequiredAriaProps;
|
||||
use crate::tester::Tester;
|
||||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"components": {
|
||||
"MyComponent": "div",
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let pass = vec![
|
||||
("<Bar baz />", None, None, None),
|
||||
("<div />", None, None, None),
|
||||
("<div></div>", None, None, None),
|
||||
("<div role={role} />", None, None, None),
|
||||
("<div role={role || 'button'} />", None, None, None),
|
||||
("<div role={role || 'foobar'} />", None, None, None),
|
||||
("<div role='row' />", None, None, None),
|
||||
("<span role='checkbox' aria-checked='false' aria-labelledby='foo' tabindex='0'></span>", None, None, None),
|
||||
("<input role='checkbox' aria-checked='false' aria-labelledby='foo' tabindex='0' {...props} type='checkbox' />", None, None, None),
|
||||
("<input type='checkbox' role='switch' />", None, None, None),
|
||||
("<MyComponent role='checkbox' aria-checked='false' aria-labelledby='foo' tabindex='0' />", None, Some(settings()), None),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
("<div role='slider' />", None, None, None),
|
||||
("<div role='slider' aria-valuemax />", None, None, None),
|
||||
("<div role='slider' aria-valuemax aria-valuemin />", None, None, None),
|
||||
("<div role='checkbox' />", None, None, None),
|
||||
("<div role='checkbox' checked />", None, None, None),
|
||||
("<div role='checkbox' aria-chcked />", None, None, None),
|
||||
("<span role='checkbox' aria-labelledby='foo' tabindex='0'></span>", None, None, None),
|
||||
("<div role='combobox' />", None, None, None),
|
||||
("<div role='combobox' expanded />", None, None, None),
|
||||
("<div role='combobox' aria-expandd />", None, None, None),
|
||||
("<div role='scrollbar' />", None, None, None),
|
||||
("<div role='scrollbar' aria-valuemax />", None, None, None),
|
||||
("<div role='scrollbar' aria-valuemax aria-valuemin />", None, None, None),
|
||||
("<div role='scrollbar' aria-valuemax aria-valuenow />", None, None, None),
|
||||
("<div role='scrollbar' aria-valuemin aria-valuenow />", None, None, None),
|
||||
("<div role='heading' />", None, None, None),
|
||||
("<div role='option' />", None, None, None),
|
||||
("<MyComponent role='combobox' />", None, Some(settings()), None),
|
||||
];
|
||||
|
||||
Tester::new_with_settings(RoleHasRequiredAriaProps::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: role_has_required_aria_props
|
||||
---
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `slider` role is missing required aria props `aria-valuenow`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='slider' />
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuenow` to the element with `slider` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `slider` role is missing required aria props `aria-valuemin`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='slider' />
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemin` to the element with `slider` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `slider` role is missing required aria props `aria-valuemax`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='slider' />
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemax` to the element with `slider` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `slider` role is missing required aria props `aria-valuenow`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='slider' aria-valuemax />
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuenow` to the element with `slider` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `slider` role is missing required aria props `aria-valuemin`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='slider' aria-valuemax />
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemin` to the element with `slider` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `slider` role is missing required aria props `aria-valuenow`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='slider' aria-valuemax aria-valuemin />
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuenow` to the element with `slider` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `checkbox` role is missing required aria props `aria-checked`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='checkbox' />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-checked` to the element with `checkbox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `checkbox` role is missing required aria props `aria-checked`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='checkbox' checked />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-checked` to the element with `checkbox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `checkbox` role is missing required aria props `aria-checked`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='checkbox' aria-chcked />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-checked` to the element with `checkbox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `checkbox` role is missing required aria props `aria-checked`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <span role='checkbox' aria-labelledby='foo' tabindex='0'></span>
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-checked` to the element with `checkbox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='combobox' />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `combobox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-expanded`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='combobox' />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-expanded` to the element with `combobox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='combobox' expanded />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `combobox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-expanded`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='combobox' expanded />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-expanded` to the element with `combobox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='combobox' aria-expandd />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `combobox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-expanded`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='combobox' aria-expandd />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-expanded` to the element with `combobox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-orientation`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-orientation` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuemax`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemax` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuemin`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemin` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuenow`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuenow` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-orientation`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-orientation` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuemin`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemin` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuenow`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuenow` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-orientation`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax aria-valuemin />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-orientation` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax aria-valuemin />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuenow`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax aria-valuemin />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuenow` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-orientation`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax aria-valuenow />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-orientation` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuemin`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax aria-valuenow />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemin` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemax aria-valuenow />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-orientation`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemin aria-valuenow />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-orientation` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-valuemax`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemin aria-valuenow />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-valuemax` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `scrollbar` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='scrollbar' aria-valuemin aria-valuenow />
|
||||
· ────────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `scrollbar` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `heading` role is missing required aria props `aria-level`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='heading' />
|
||||
· ──────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-level` to the element with `heading` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `option` role is missing required aria props `aria-selected`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <div role='option' />
|
||||
· ─────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-selected` to the element with `option` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-controls`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <MyComponent role='combobox' />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-controls` to the element with `combobox` role.
|
||||
|
||||
⚠ eslint-plugin-jsx-a11y(role-has-required-aria-props): `combobox` role is missing required aria props `aria-expanded`.
|
||||
╭─[role_has_required_aria_props.tsx:1:1]
|
||||
1 │ <MyComponent role='combobox' />
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Add missing aria props `aria-expanded` to the element with `combobox` role.
|
||||
|
||||
|
||||
Loading…
Reference in a new issue