Focusing text field after navigation, why does it work in Vue but not React or Svelte? #14423
Replies: 1 comment 2 replies
-
|
yeah so you've basically figured it out already. vue's reactivity and vue router work synchronously — when you tap a RouterLink, the route change, component mount, and your focus call all happen in the same call stack as the original click event. ios safari sees that whole chain as still being part of the user interaction so it allows the keyboard to open. react breaks this chain. react's useEffect/useLayoutEffect runs after async state updates and reconciliation. by that point safari no longer considers it a trusted user gesture so it suppresses the keyboard. you can see the css focus styles because the element IS focused in the dom sense, safari just won't show the keyboard without that trust chain. its mostly a happy accident from vue's design. they chose synchronous reactivity and dom patching for predictability, not specifically for ios safari compat, but it happens to satisfy safari's requirements. the common workaround for react is to focus a temporary hidden input synchronously inside the click handler (which opens the keyboard while still in trusted context), then transfer focus to your real input after the page mounts: function SearchLink() {
const handleClick = () => {
const tmp = document.createElement('input');
tmp.style.position = 'fixed';
tmp.style.opacity = '0';
document.body.appendChild(tmp);
tmp.focus(); // keyboard opens — still in trusted context
requestAnimationFrame(() => {
const real = document.querySelector('#search-input');
if (real) real.focus();
tmp.remove();
});
};
return <Link to="/search" onClick={handleClick}>Search</Link>;
}ugly but it works because safari keeps the keyboard open once its already showing. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm scratching my head over a thing that I've noticed when trying to programatically focus an input text field in Vue, React and Svelte. The way I want to set it up is to have a /search page. Whenever the page is mounted or activated, the field should be focused. That is simple, but the problem is that iOS Safari prevents fields from being focused (truly focused with the keyboard showing) without a user interaction triggering it.
The funny but also annoying thing is that this works in Vue without issues. I have a
<RouterLink>that goes to the/searchpage. I then use a ref to the field and focus on that withthis.$refs.field.focus()inmounted()with the Options API. And it just works, the field gets focused and the keyboard shows. But recreating the same logic in React or Svelte, the field never gets the keyboard to show. I can see that the CSS focus state is applied to the field, but no keyboard appears.So I've aksed ChatGPT and Claude about this, and after many failed suggestions and assumptions I think I've reached the conclusion that this is either the fact that Vue Router is synchrounous (?) and that the click of the RouterLink is evaluated and accepted as a user interaction that can be chained to focus the field. Or that the RouterLink itself is constructed in a way that it either through a click or touch event manages to follow through until the new page is mounted and the focus is then accepted there.
Does anyone know what kind of quirk in Vue that makes this work there? And is it intended or a happy accident?
Beta Was this translation helpful? Give feedback.
All reactions