floating-ui / react-popper

🍿⚛Official React library to use Popper, the positioning library
https://popper.js.org/react-popper/
MIT License
2.5k stars 226 forks source link

Portalled popper with autoFocus content #395

Closed mattfelten closed 3 years ago

mattfelten commented 3 years ago

Reproduction demo

https://codesandbox.io/s/zen-hofstadter-9xwtp?file=/src/App.js

Steps to reproduce the problem

  1. Have element with autoFocus appear within portalled Popper
  2. Make sure target is not at the top of the page
  3. Watch page scroll when Popper appears

What is the expected behavior?

I do understand why this is happening. A portalled Popper is set to 0,0 initially and then positioned accordingly. The autoFocus element is immediately rendered, at around 0,0, and the window scrolls to that position as default behavior.

There are a few other Issues around that solves this in a few ways, one being to change how focus is applied. This is not doable in my case, the content is dynamic.

Some ideas I haven't fully worked out:

Any ideas to solve this?

Packages versions

FezVrasta commented 3 years ago

Can't you set the tabIndex to -1 before the popper is positioned?

mattfelten commented 3 years ago

Adding tabIndex: -1 in the CodeSandbox example above does not seem to do anything. I need autoFocus to still work, it makes a good experience, I'm just trying to prevent the page scroll from popper positioning. Any other ideas?

piecyk commented 3 years ago

You can always manually focus the input after react using setTimeout

const UnchangableContent = () => {
  const inputRef = useRef();

  useEffect(() => {
    setTimeout(() => {
      inputRef.current.focus();
    }, 0);
  }, []);

  return <input ref={inputRef} type="text" />;
};

https://codesandbox.io/s/naughty-yalow-0h30k

mattfelten commented 3 years ago

I'm not able to change UnchangableContent. It's dynamic content that I don't have control over.

What I'm trying to do is get around the 0,0 initial positioning in a way that when an autoFocus element is mounted, that it's in the right place and doesn't scroll the screen.

piecyk commented 3 years ago

I'm not able to change UnchangableContent. It's dynamic content that I don't have control over.

Ok, basic you can use the same setTimeout hack to defer the rendering of UnchangableContent content

Update the code sandbox https://codesandbox.io/s/naughty-yalow-0h30k

mattfelten commented 3 years ago

Ah interesting. That might work. I'll try it out.

piecyk commented 3 years ago

I think there is nothing to do on react-popper side regarding this, could we close the issue @mattfelten?