tailwindlabs / headlessui

Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.
https://headlessui.com
MIT License
25.81k stars 1.07k forks source link

Ensure page doesn't scroll down when pressing `Escape` to close the `Dialog` component #3218

Closed RobinMalfait closed 4 months ago

RobinMalfait commented 4 months ago

This PR ensures that the page doesn't scroll down when pressing Escape to close an open Dialog component.

This only happens in Safari, and if the document.activeElement is an <input> for example. It also only happens when pressing Escape, not when clicking outside of the Dialog component.

The reason why is a bit confusing but it does make sense:

Whenever the the currently focused element is moved on the page, Safari will try to keep the document.activeElement in view. This means that when you press Escape that the <input> element is still focused, but since the Dialog closes, the <input> is still rendered in a portal at the end of the page. Because it's rendered there, Safari will try and keep it in view, which causes the page to scroll down.

It doesn't happen when clicking outside of the Dialog component because the document.activeElement will be the newly focused element, which is typically the <body> element.

To solve this, we will always call document.activeElement.blur() (which is also implicitly done when clicking outside of the Dialog component) when we press Escape.

Now, the <input> element is no longer focused, and Safari won't try to keep it in view, which prevents the page from scrolling down.

vercel[bot] commented 4 months ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
headlessui-react ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 20, 2024 2:20pm
headlessui-vue ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 20, 2024 2:20pm