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

Elements loose focus when moving to or from a portal #12454

Closed
alexreardon opened this issue Mar 26, 2018 · 8 comments
Closed

Elements loose focus when moving to or from a portal #12454

alexreardon opened this issue Mar 26, 2018 · 8 comments

Comments

@alexreardon
Copy link

Do you want to request a feature or report a bug?

Perhaps a bug, but could also be seen as a feature

What is the current behavior?

When you move an element to a portal through ReactDOM.createPortal the element looses focus if it had focus. If the element gains focus while in a portal, when moving out of the portal it looses focus.

What is the expected behavior?

I would have expected React to maintain focus of the element when moving in or out of a portal

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

Tested with

React version: 16.2
Browsers: Latest chrome and firefox. I did not test others but expect the behaviour to be the same
OS: Tested on Mac High Sierra

@suhailnaw
Copy link

I'm going to attempt to replicate the issue in a JSFiddle. I'm looking to make my first contribution so if it's an actual bug, I'd like to take a try at a fix.

@dantman
Copy link
Contributor

dantman commented Mar 28, 2018

Focus loss is not a bug in react, nor is this currently being cased by a focus loss bug.

Firstly, React does not currently have the ability to move something rendered by react from one parent to another, even involving Portals (unless you move the portal container itself). As a result what you are currently experiencing is not your element losing focus, it is your element being destroyed completely and a completely different element being created which of course doesn't have focus.

However even if React did support reparenting (or you used appendChild yourself to move a portal or move the container element that React is being rendered to), you would still see focus being lost. This is not a bug in any library.

At the most basic fundamental level if you use appendChild/insertChild to move a focused input from one part of the dom tree to another part of the dom tree. That input will loose focus. Chrome, Firefox, Safari, and even IE11 all consistently follow this behaviour.

https://dantman.github.io/dom-reparent-tests/focus.html

Ultimately if you want focus to be retained when moving things between parents, you are going to have to manage focus yourself. The upcoming getSnapshotBeforeUpdate lifecycle hook may help with this. Though the fundamental reparenting issue will also need to be solved.

@alexreardon
Copy link
Author

Thanks for the detail @dantman. Agreed that it is not a bug. However, it could be a feature of react to maintain focus across a portal. My guess is that it would be extremely common to retain focus during a portal transition - even if the underlying DOM operations cause a focus lost. It feels like a similar concern to how react maintains scroll position even after DOM updates

Thanks for looking into this!

@gaearon
Copy link
Collaborator

gaearon commented Aug 2, 2018

Closing because this is not really about portals or focus — it's about reparenting (for which we have other issues).

@gaearon gaearon closed this as completed Aug 2, 2018
@naisergic
Copy link

naisergic commented Apr 26, 2020

@dantman
@gaearon
could you guys help me in understanding the 2 examples I have created with ReactDom.createPortal, In one input text is maintaining focus and with other focus gets lost.

https://codesandbox.io/s/portal-maintaining-focus-kzufj
https://codesandbox.io/s/portal-loosing-focus-965m6

I have not done anything extra to maintain the focus, just use the portal like
ReactDom.createPortal(component(),document.body) instead of
ReactDom.createPortal(<Component/>, document.body)

@dantman
Copy link
Contributor

dantman commented Apr 26, 2020

Take a look at this modification to your second example.
https://codesandbox.io/s/portal-loosing-focus-b9b0k

Your ModalContainer component function is defined inside of your Portal component. So every time Portal renders a new ModalContainer function is created. Because the component is different this results in the previous component and your input being completely unmounnted and a new tree with the new ModelContainer component is rendered.

@naisergic
Copy link

@dantman ,
Thanks for explaining :-) , but one question I have used the same approach in example 1 which maintains the focus, in that also I have defined the function inside the Portal component

@dantman
Copy link
Contributor

dantman commented Apr 26, 2020

@naisergic In the first example the function is not a component, you use it and pass it's return value to the portal. It works exactly the same as if the function didn't exist.

i.e. The first example works as if you wrote this instead:
https://codesandbox.io/s/portal-maintaining-focus-mk2gt

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

No branches or pull requests

5 participants