Router: Navigating blurs inputs with `autoFocus`

Created on 15 Jan 2019  路  4Comments  路  Source: reach/router

This is related to #158 - navigating to a page with an autofocused input still causes the input to be focused and blurred immediately on navigation. This breaks things like wizard-style form navigation where input validation fires on input blur - the validation improperly fires before a user ever focuses the input.

Here is a sandbox (modified from #158) that provides a minimal demonstration with v1.2.1:
https://codesandbox.io/s/3yppojk23q

I made a fork of the router and used that in my project for the time being. The fix that worked for me was changing requestFocus to match the change in a7a1c84e7f518611d0de2fe4606e17d453fd51eb

requestFocus = node => { if (!this.state.shouldFocus && !node.contains(document.activeElement)) { node.focus(); } };

potential bug

Most helpful comment

I fixed a similar issue by using <Router primary={false}> so that the Router doesn't interfere with focus at all.

However, I do see a problem with this solution: if "primary" is a concept that involves more than focus, then maybe I want my Router to primary. It would be good if the docs explain what "primary" really means. Possibly, it would be an improvement to use a separate "manageFocus" attribute (where manageFocus=false is implied if it's not the primary router).

All 4 comments

Workaround for now (if using hooks):

useLayoutEffect(() => {
  elementToFocusRef.current.focus();
}, []);

Don't use useEffect because it will fire after router focus and you'll get two of them. useLayoutEffect fires synchronously right after DOM mutations and prevents router focus.

This can also be used if you need to focus other elements with tabindex, e.g if using custom scrollbar and scrollable content is deeper in hierarchy, wouldn't scroll with arrow keys if router div is focused.

Attribute autofocus is only supported on 4 HTML elements as far as I know.

I fixed a similar issue by using <Router primary={false}> so that the Router doesn't interfere with focus at all.

However, I do see a problem with this solution: if "primary" is a concept that involves more than focus, then maybe I want my Router to primary. It would be good if the docs explain what "primary" really means. Possibly, it would be an improvement to use a separate "manageFocus" attribute (where manageFocus=false is implied if it's not the primary router).

It would be good if the docs explain what "primary" really means.

One important thing it does is setting height: 100%. Would be great to have it separate from focus manipulation.

Easy fix is just creating a wrapper since Router passes classNames down to the rendered div.

We're experiencing this same issue, specifically when using nested routes. In our case, we want to update the URL to reflect a string that a user types into a text box. This navigation doesn't result in a different page being rendered, but if the page is inside a nested route, focus gets stolen from the text box. If the page is NOT in a nested route, everything works fine

Here's a minimal example: https://codesandbox.io/s/stoic-darkness-s3ejs

Was this page helpful?
0 / 5 - 0 ratings

Related issues

artoodeeto picture artoodeeto  路  4Comments

alexluong picture alexluong  路  3Comments

kbrgl picture kbrgl  路  4Comments

florian-bd picture florian-bd  路  3Comments

ryanflorence picture ryanflorence  路  4Comments