Skip to content

Commit

Permalink
[new] Add basic suggestions for interactive-supports-focus
Browse files Browse the repository at this point in the history
Add basic support for ESlint rule suggestions for the `interactive-supports-focus` for tabIndex values when elements are interactive but do not have implicit focusable browser behaviour.
These are intentionally not auto-fix but simply optional suggestions to help developers resolve their issue.

Fixes jsx-eslint#952
See also jsx-eslint#951
  • Loading branch information
lb- committed Oct 23, 2024
1 parent e5dda96 commit 118498e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
17 changes: 16 additions & 1 deletion __tests__/src/rules/interactive-supports-focus-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function template(strings, ...keys) {
const ruleName = 'interactive-supports-focus';
const type = 'JSXOpeningElement';
const codeTemplate = template`<${0} role="${1}" ${2}={() => void 0} />`;
const fixedTemplate = template`<${0} tabIndex={${1}} role="${2}" ${3}={() => void 0} />`;
const tabindexTemplate = template`<${0} role="${1}" ${2}={() => void 0} tabIndex="0" />`;
const tabbableTemplate = template`Elements with the '${0}' interactive role must be tabbable.`;
const focusableTemplate = template`Elements with the '${0}' interactive role must be focusable.`;
Expand All @@ -47,7 +48,14 @@ const componentsSettings = {
},
};

const buttonError = { message: tabbableTemplate('button'), type };
const buttonError = {
message: tabbableTemplate('button'),
suggestions: [{
desc: 'Add `tabIndex={0}` to make the element focusable in sequential keyboard navigation.',
output: '<Div tabIndex={0} onClick={() => void 0} role="button" />',
}],
type,
};

const recommendedOptions = configs.recommended.rules[`jsx-a11y/${ruleName}`][1] || {};

Expand Down Expand Up @@ -202,6 +210,13 @@ const failReducer = (roles, handlers, messageTemplate) => (
errors: [{
type,
message: messageTemplate(role),
suggestions: [{
desc: 'Add `tabIndex={0}` to make the element focusable in sequential keyboard navigation.',
output: fixedTemplate(element, '0', role, handler),
}].concat(messageTemplate === focusableTemplate ? [{
desc: 'Add `tabIndex={-1}` to make the element focusable but not reachable via sequential keyboard navigation.',
output: fixedTemplate(element, '-1', role, handler),
}] : []),
}],
})))
), []))
Expand Down
27 changes: 27 additions & 0 deletions src/rules/interactive-supports-focus.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export default ({
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md',
description: 'Enforce that elements with interactive handlers like `onClick` must be focusable.',
},
hasSuggestions: true,
messages: {
'tabIndex=0': 'Add `tabIndex={0}` to make the element focusable in sequential keyboard navigation.',
'tabIndex=-1': 'Add `tabIndex={-1}` to make the element focusable but not reachable via sequential keyboard navigation.',
},
schema: [schema],
},

Expand Down Expand Up @@ -100,12 +105,34 @@ export default ({
context.report({
node,
message: `Elements with the '${role}' interactive role must be tabbable.`,
suggest: [
{
messageId: 'tabIndex=0',
fix(fixer) {
return fixer.insertTextAfter(node.name, ' tabIndex={0}');
},
},
],
});
} else {
// Focusable, tabIndex = -1 or 0
context.report({
node,
message: `Elements with the '${role}' interactive role must be focusable.`,
suggest: [
{
messageId: 'tabIndex=0',
fix(fixer) {
return fixer.insertTextAfter(node.name, ' tabIndex={0}');
},
},
{
messageId: 'tabIndex=-1',
fix(fixer) {
return fixer.insertTextAfter(node.name, ' tabIndex={-1}');
},
},
],
});
}
}
Expand Down

0 comments on commit 118498e

Please sign in to comment.