-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A11y: Introduce ClickableElement #7977
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #7977 +/- ##
==========================================
+ Coverage 73.05% 73.06% +0.01%
==========================================
Files 1299 1300 +1
Lines 40372 40376 +4
Branches 7506 7505 -1
==========================================
+ Hits 29492 29500 +8
+ Misses 10880 10876 -4 ☔ View full report in Codecov by Sentry. |
> = ({ children, ...props }) => ( | ||
<div | ||
{...props} | ||
tabIndex={0} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why specify the tabIndex specifically as 0? Won't this mess up the tab order on the page?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would set tabIndex={0} before spreading props, so we can choose to override it otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, 0 value basically will let the dom auto-order these focusable elements.
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea in theory, but in practice we should never set tabIndex > 0 https://webaim.org/techniques/keyboard/tabindex#tabindex
* - https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/mouse-events-have-key-events.md | ||
* | ||
*/ | ||
const ClickableElement: React.FC< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also probably include some default styling for cursor: pointer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be best to address that globally, for all role=button, via CSS. I can open a followup PR that takes care of all existing definitions for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good to me
src/components/ClickableElement.tsx
Outdated
props.onClick(event); | ||
} | ||
}} | ||
// TODO: also handle onMouseOver -> onFocus |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What custom logic were you thinking for these events?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's part of one of the a11y rules linked above. However in reality we should just avoid such events and use CSS instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha. It wasn't clear from this TODO comment what it was referring to.
It seems like this could be addressed with some TS discriminated unions but I'm also not sure we even want to always enforce this rule. For example, a popular pattern for form inputs is to autosave onBlur, but not onMouseLeave.
const handleClick = jest.fn(); | ||
render(<ClickableElement onClick={handleClick} />); | ||
const clickableElement = screen.getByRole("button"); | ||
fireEvent.keyPress(clickableElement, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: why not use userEvent.keyboard?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was copiloted. I can change it if you prefer
What does this PR do?
This component and lint rule essentially replaces most instances of:
This also documents the usage of clickable
div
elements and ensures consistent/safe usage.Checklist