Skip to content
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

fix: keyboard interaction for popover #793

Merged
merged 10 commits into from
Nov 21, 2019
Merged

Conversation

jacobdevera
Copy link
Contributor

@jacobdevera jacobdevera commented Nov 15, 2019

Description

  • focus the first element in the popover when opened, and traps focus within popover until closed with Escape key
  • allows other elements in the popover to be interacted with (e.g. buttons, inputs, other popovers)
  • returns focus to the element that opened the popover when closed with Escape key

popover-keyboard-test 2019-11-15 10_20_23

@jacobdevera jacobdevera self-assigned this Nov 15, 2019
@CLAassistant
Copy link

CLAassistant commented Nov 15, 2019

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@netlify
Copy link

netlify bot commented Nov 15, 2019

Deploy preview for fundamental-react ready!

Built with commit bc64b61

https://deploy-preview-793--fundamental-react.netlify.com

@jacobdevera jacobdevera requested a review from a team November 15, 2019 18:27
@@ -88,6 +88,7 @@ class Popper extends React.Component {

let popper = (
<ReactPopper
{...popperProps}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

innerRef could not be set without the props going to this level because it only exists in react-popper.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might need an additional prop then to spread to the inner div

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to just separate the ref out from the popperProps. Don't think there would be a need to have two sets of props to spread.

@meganaconley
Copy link
Contributor

The combobox can't be navigated into with the arrow key. Is this due to keyboard issues of the list inside or can we fix this here?
If it's due to the list component let's make a follow up task to fix that.

Copy link
Contributor

@meganaconley meganaconley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, QA completed and now the keyboard handling is up to spec.

@jacobdevera jacobdevera merged commit 8cf5555 into master Nov 21, 2019
@jacobdevera jacobdevera deleted the fix/keyboard-interaction branch November 21, 2019 20:31
@ChristianKienle
Copy link

I have a question – and a comment. :)

Fundamental Vue also has a Popover-component. I also thought about where to add things like keyboard-handling, trapping, … and in the end (at least as of now) I decided to not implement those things in the Popover component itself.

Those kind of things are implemented in the components that use the popover component.

The reason was the realization that this makes it more straight forward to re-use the popover component for a multitude of other things. For example I am also using the popover for popovers that are shown "on hover" and in that case I don't want any focus trapping to happen – also ESC should not be captured/handled by the popover that just acts as a tooltip…

What are your thoughts on this? Maybe I am also over-engineering things… :D

@jacobdevera
Copy link
Contributor Author

jacobdevera commented Dec 2, 2019

@ChristianKienle Good points. 🙂 I think this boils down to what a Popover component really is. Searching around, it seems many component libraries make a distinct differentiation—a Popover is explicitly triggered by click/key press; whereas a Tooltip strictly appears on mouse hover/keyboard focus.
e.g. Bootstrap:
https://getbootstrap.com/docs/4.4/components/popovers/
https://getbootstrap.com/docs/4.4/components/tooltips/

But this isn't consistent, as react-bootstrap uses tooltips that need to be activated as well, with the main differentiation from its popover being the styling.

We don't really have a Tooltip equivalent in Fundamental, but the majority of the keyboard handling is in the separate focusManager class, besides the escape key handling from what I can see. Perhaps keyboard handling could be made optional via a prop to make it act as a tooltip, but I'm not sure how else I'd compose the Popover differently. To me, it seems the base popper is the true abstraction, and Popover is just an implementation of it.

@ChristianKienle
Copy link

@jacobdevera Take the date-input + calendar component as an example.

Screenshot 2019-12-03 at 11 12 06

In Fundamental Vue this component is simply using the popover component + a date input component + the calendar. Once you click on the input the calendar appears. While the calendar is open you still want to be able to use the input (typing in a data + using the arrow keys + esc). Isn't that a use case where you would have to "turn off" almost every special keyboard-handling + focus trapping code?

The popover in Fundamental Vue is really just a div that is rendered on top of everything else + managed by popper.js.

There are special components that simply re-use the popover component but add "domain specific" things like keyboard handling, focus trapping + auto dismiss when the user interacts with elements outside of the popover.

The popover component in Fundamental Vue does not even "dismiss itself" when the user starts to interact with something outside of it. One of the reasons is the above date picker. You want the user to interact with the input element while the popover is open. :D When I realized that I first began to add props to the (back then – much smarter) popover component that could be used to toggle those features on and off. In the end I almost always had to play with those props because every time I tried to re-use the smart popover something did not feel right.

This was the point when I said to myself: "Hey – I am turning off features every time I use this component – why don't I just remove all those features then and add them later (in other components that are part of the library) where they belong to?. Then I made that change and it felt good. But I guess you are right – there is no "right" and "wrong" and definitive way to do things here. :D

Also I should mention that one part of me feels my approach is way too over engineered – it somehow makes sense in my head but is not really intuitive because you have other expectations when you hear "popover".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants