-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[UI Framework] Add KuiKeyboardAccessible component to UI Framework. #11743
[UI Framework] Add KuiKeyboardAccessible component to UI Framework. #11743
Conversation
c46aa05
to
7ddac92
Compare
// If the developer hasn't already specified attributes required for accessibility, add them. | ||
const props = Object.assign({ | ||
tabIndex: '0', | ||
role: 'button', |
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.
Shouldn't this role be applied only to elements that "appear as a button" to the user with a screenreader?
If I understand the intention, this container class would also be applied to anchor links in text - that doesn't seem like something we want 100% of the time.
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.
You're absolutely right man. I'll update this PR. I also created #11810 so that we update kbn-accessible-click
, too.
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.
To add more to my comment, the MDN docs say this role will make screenreaders announce that the element is a button. Although, it might not be a button visually, for example we will use KuiKeyboardAccessible
on an anchor tag when simply using href
is not an option (i.e. the anchor tag just has an onClick
).
If a screenreader announces something is a button when it is visually not a button, that seems like a negligible issue. Unless the way it is announced is totally confusing. That might be worth looking into. I'm ok with this as it is though.
// Support keyboard accessibility by emulating mouse click on ENTER or SPACE keypress. | ||
if (accessibleClickKeys[e.keyCode]) { | ||
// Delegate to the click handler on the element. | ||
this.props.children.props.onClick(e); |
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.
Have you thought about making SPACE emulate click just for button elements? I’m pretty used to having SPACE act as page down unless focus is on a button. If focus is on a link, it should just be an ENTER keypress to emulate a click.
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.
Thanks for catching this, great point.
After talking about this with @tsullivan we agreed that it doesn't make sense to use this component on an element which is acting as a link. In that case, you'd just use an anchor tag with an href. It only makes sense to use this component on an element which acts as a button or otherwise responds to the SPACE keypress, like checkboxes and radio buttons. See http://webaim.org/techniques/keyboard/ for more info on these types of elements. |
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.
LGTM. Seems to work as expected. Just some minor comments, feel free to skip any of them.
}, child.props, { | ||
// We don't want to allow the child to overwrite these handlers. | ||
onKeyDown: this.onKeyDown, | ||
onKeyUp: this.onKeyUp, |
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.
Maybe throw errors in the proptypes stuff below if you override these? (It can be annoying to debug if you add onKeyUp
and your function is just never called ;))
(We don't use them often, but there are a couple of keyDown uses in the app, at least)
} | ||
|
||
applyKeyboardAccessibility(child) { | ||
// If the developer hasn't already specified attributes required for accessibility, add them. |
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.
Maybe "Add attributes required for accessibility unless they are already specified"?
|
||
applyKeyboardAccessibility(child) { | ||
// If the developer hasn't already specified attributes required for accessibility, add them. | ||
const props = Object.assign({ |
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'd probably write this as:
const props = {
tabIndex: '0',
role: 'button',
...child.props,
onKeyDown: this.onKeyDown,
onKeyUp: this.onKeyUp,
}
I just think it reads better than Object.assign
} | ||
|
||
// Support keyboard accessibility by emulating mouse click on ENTER or SPACE keypress. | ||
if (accessibleClickKeys[e.keyCode]) { |
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.
nitpick. I think I'd prefer e.keyCode === ENTER_KEY || e.keyCode === SPACE_KEY
, just to be clear. Or maybe make it a function instead isAccessibleClickKey(e.keyCode)
? (I just think it reads better)
In either case I think the comment can be removed.
|
||
<KuiKeyboardAccessible> | ||
<div onClick={() => window.alert('Div clicked')}> | ||
Click this div, which itself contains another acessible element: |
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 we should specify the expectation/intention here (when you click on the inner KuiKeyboardAccessible
it triggers both onClick
s).
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 catch... I think this is actually a bug. We only want the child's click handler to be called it's clicked.
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.
Hmm, on second thought, you're right. That is the expected behavior. I need to update the SPACE and ENTER keypress handlers to mirror this behavior.
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'm not sure if it should trigger both or not. I was mostly commenting because it did trigger both when I played around with this and I wasn't sure if it was expected or not, so my comment was just about making intention/expectation clear in the "Click this div" text.
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.
Cool, thanks. I looked into it and I decided that the onClick on the parent element should be responsible for comparing the event's target and currentTarget, instead of making that the responsibility of this component.
…ents. This mirrors mouse click behavior. - Throw errors if KuiKeyboardAccessible child has onKeyDown or onKeyUp props. - Refine syntax and improve comments.
7ddac92
to
8e4a06d
Compare
onKeyUp: this.onKeyUp, | ||
}; | ||
|
||
return cloneElement(child, props); |
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.
pretty cool
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.
LGTM 🎆
…lastic#11743) * Move accessibleClickKeys service into UI Framework. * Add KuiKeyboardAccessible component to UI Framework. * Change KuiKeyboardAccessible and kbn-accessible-click to propagate events. This mirrors mouse click behavior.
…lastic#11743) * Move accessibleClickKeys service into UI Framework. * Add KuiKeyboardAccessible component to UI Framework. * Change KuiKeyboardAccessible and kbn-accessible-click to propagate events. This mirrors mouse click behavior.
This React component is an analogue to the
kbn-accessible-click
directive introduced in #11591. You can wrap an element within this component to make it keyboard-accessible per #11513.CC @Bargs if you're interested.