-
Notifications
You must be signed in to change notification settings - Fork 63
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 issue with returnFocusOnDeactivate
not working when active
pr…
#54
Conversation
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.
@krikienoid Thanks for making an attempt at this, and I'm sorry your PR has gone so long without response. The project went quiet for a while, and I'm trying to take over now.
I did some digging and found the issue. It's related timing, the ESC key handling in focus-trap
, and this line: https://github.com/focus-trap/focus-trap/blob/master/index.js#L111
If you test with the "special element" example, you can reproduce this bug by hitting ESC to deactivate the trap instead of clicking on the "deactivate" button. This is the sequence of events that ensues:
-
focus-trap
'sdeactivate()
method gets called thanks to its ESC key handler and immediately deactivates the trap at https://github.com/focus-trap/focus-trap/blob/master/index.js#L98NOTE: The trap was created with
returnFocusOnDeactivate: false
thanks tofocus-trap-react
's special handling of that feature here: https://github.com/focus-trap/focus-trap-react/blob/master/src/focus-trap-react.js#L28 -
focus-trap-react
'scomponentDidUpdate()
handler then gets called, determines the trap should no longer be active because theactive
prop is nowfalse
so it creates the deactivateconfig
withreturnFocus: true
becausereturnFocusOnDeactivate: true
was provided as initial trap options. It then calls https://github.com/focus-trap/focus-trap-react/blob/master/src/focus-trap-react.js#L69 but this does nothing because of https://github.com/focus-trap/focus-trap/blob/master/index.js#L90 which determines the trap is no longer active and returns immediately. SoreturnFocus: true
is lost here. -
Execution returns to https://github.com/focus-trap/focus-trap/blob/master/index.js#L98 and continues to https://github.com/focus-trap/focus-trap/blob/master/index.js#L108-L111 where
deactivateOptions === undefined
(because this call intodeactivate()
came from the ESC key handler, NOTcomponentDidUpdate()
...) and we fallback to https://github.com/focus-trap/focus-trap/blob/master/index.js#L111 which determinesreturnFocusOnDeactivate: false
(because of https://github.com/focus-trap/focus-trap-react/blob/master/src/focus-trap-react.js#L28) and therefore focus is NOT returned to the "activate" button.
That's the series of unfortunate events.
I think the cause of the issue is that the component references this.previouslyFocusedElement when mounting/unmounting but not when a prop is updated.
Your solution, while it may work, attempts to accomplish some work that focus-trap
should be handling instead. I'd like to see if there's a way to let focus-trap
do its thing. Any ideas?
And the 'special element' demo is now set to return focus after deactivation, in particular to make it easier to reproduce the issue that focus is NOT returned when deactivating with the ESC key, which is the issue #54 is trying to fix.
And the 'special element' demo is now set to return focus after deactivation, in particular to make it easier to reproduce the issue that focus is NOT returned when deactivating with the ESC key, which is the issue #54 is trying to fix.
And the 'special element' demo is now set to return focus after deactivation, in particular to make it easier to reproduce the issue that focus is NOT returned when deactivating with the ESC key, which is the issue #54 is trying to fix.
Hey, I've just ran into this bug and I am not very familiar with open-source so I apologize if this is not the correct place to comment this, if it is I'd be happy to remove it. First of all thanks for maintaining this package! By what I could understand of the comment focus-trap-react/src/focus-trap-react.js Lines 21 to 25 in 6a80deb
focus-trap-react wrapper isn't using the focus-trap intended way of capturing the previously focused element, most likely because of the limitation described there. So it implements a hacky way of dealing with that by saving it on the component and updating it properly on mount/unmount.
Probably the interaction of the One alternative I see is adding a function on So the lines https://github.com/focus-trap/focus-trap-react/blob/6a80debd55ec76cfeaeb8fdea67c4c8952bd75ce/src/focus-trap-react.js#L52-55 the tailoredFocusTrapOptions would look like something along the lines const newTailoredFocusTrapOptions = {
...tailoredFocusTrapOptions,
onDeactivate: () => {
if(tailoredFocusTrapOptions.onDeactivate) {
tailoredFocusTrapOptions.onDeactivate()
}
if (
this.props.focusTrapOptions.returnFocusOnDeactivate !== false &&
this.previouslyFocusedElement &&
this.previouslyFocusedElement.focus
) {
this.previouslyFocusedElement.focus();
}
}
} Which will probably mean that we can remove the check https://github.com/focus-trap/focus-trap-react/blob/6a80debd55ec76cfeaeb8fdea67c4c8952bd75ce/src/focus-trap-react.js#L66-68 and https://github.com/focus-trap/focus-trap-react/blob/6a80debd55ec76cfeaeb8fdea67c4c8952bd75ce/src/focus-trap-react.js#L83-89 This still doesn't solve the issue that you brought that |
I'm having trouble understanding what is going on with the code, but it sounds like focus-trap-react needs to call the deactivate method twice in order to work, and the config settings are getting lost between the two calls, to put it simply. I'm thinking maybe this could be fixed by making sure the settings are always passed in the escape key method. I haven't had a chance to test this out, but I'm thinking of modifying this method to something like this: https://github.com/focus-trap/focus-trap/blob/master/index.js#L261
|
@JoSuzuki @krikienoid Thanks to both of you for your thoughts on this bug! 😄 Since I added my thoughts last Aug 29, focus-trap/focus-trap#103 has surfaced, which seems at least partly related, and is a bug that should be fixed over in Before determining that the fix to this issue we're discussing here belongs either here or in I'm trying to get that one done. Fix is easy, but I have to add tests, etc. That's taking a bit of time (to find time), but it's my current focus. Once I've got the fix in, I'll publish, and then it'll be easier to test over here. I'm not sure it'll fix the problem, but worth seeing the effects in case it helps. There's also the problem here in I do like the idea of leveraging |
FYI, focus-trap/focus-trap#103 has been fixed and published as |
This is a new fix for the issue identified in #54 after gaining a better understanding of the issue. The `returnFocusOnDeactivate` flag was being special-cased, but not always, and the element to which focus should be returned, which focus-trap-react attempts to manage on its own (see class Constructor comment for reasoning), was not always correct. For example, if the trap was deactivated, and then re-activated, the 'last focused element before activation' wasn't updated at the moment of re-activation, where it could've changed.
@JoSuzuki @krikienoid I did some work on this over on #139 and I think I've fixed it. If one of you could somehow test my changes with your code and let me know, I'd really appreciate it. I did address the behavior I brought-up earlier with the "special element" test and the ESC key, and I also found a couple of other things to fix, all related, along the way. |
@JoSuzuki @krikienoid I'd love for one of you to check out #139 if you have the time. I think I have a good fix, but it's kind of a shot in the dark WRT to your specific issues related to the |
I took a quick look at #139 and it appears to have fixed the issue! |
@krikienoid Thank you very much for checking it out! I will merge it, then, and publish in the next few days. |
@all-contributors add @krikienoid for bug |
@all-contributors add @JoSuzuki for bug |
I've put up a pull request to add @krikienoid! 🎉 |
I've put up a pull request to add @JoSuzuki! 🎉 |
Closing in favor of the implementation/fix in #139 |
) This is a new fix for the issue identified in #54 after gaining a better understanding of the issue. The `returnFocusOnDeactivate` flag was being special-cased, but not always, and the element to which focus should be returned, which focus-trap-react attempts to manage on its own (see class Constructor comment for reasoning), was not always correct. For example, if the trap was deactivated, and then re-activated, the 'last focused element before activation' wasn't updated at the moment of re-activation, where it could've changed.
focus-trap-react can be activated/deactivated by either mounting/unmounting the component, or by passing a boolean value to the
active
prop. When using the latter method, there is an issue where the focus is not returned on deactivation.Explicitly setting
returnFocusOnDeactivate
to true partially fixes the problem, but the issue persists when deactivation is triggered via the ESCAPE key.I think the cause of the issue is that the component references
this.previouslyFocusedElement
when mounting/unmounting but not when a prop is updated.