vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.54k stars 26.58k forks source link

Focus issue on Firefox when using `router.replace`. #54838

Open theSdev opened 1 year ago

theSdev commented 1 year ago

Verify canary release

Provide environment information

Operating System:
      Platform: linux
      Arch: x64
      Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
    Binaries:
      Node: 20.5.1
      npm: 9.8.0
      Yarn: 1.22.19
      pnpm: N/A
    Relevant Packages:
      next: 13.4.20-canary.13
      eslint-config-next: 13.4.19
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.2.2
    Next.js Config:
      output: N/A

Which area(s) of Next.js are affected? (leave empty if unsure)

Routing (next/router, next/navigation, next/link)

Link to the code that reproduces this issue or a replay of the bug

https://codesandbox.io/p/sandbox/cocky-dhawan-xz6qjj?file=/app/page.tsx:22,11

To Reproduce

Put an input in a scroll container and attach an input event listener to it. In the event handler, reflect the input's value to the URL bar using router.replace. Type something in the input.

Describe the Bug

On Firefox, the input loses focus as soon as the URL bar gets updated, Firefox gives the focus to the scroll container. The problem goes away when you switch router.replace out for browser's native history.replaceState.

Expected Behavior

The input should remain in focus.

Which browser are you using? (if relevant)

Firefox 116.0.2

How are you deploying your application? (if relevant)

No response

theSdev commented 1 year ago

I've posted a comment on Bugzilla as well, but since history.replaceState works, maybe Next can change how router.replace works under the hood?

redbmk commented 6 months ago

Not quite sure if it's the same issue but I think I'm running into this issue with Chrome as well, so may not be Firefox specific. I'm trying to update search params as I type and expecting it to update the search data from the RSC, but the input loses focus. If I set it to autoFocus, it maintains focus but depending on how fast I type and how fast the response comes back, it can sometimes lose characters.

I've tried it a couple ways:

const pathname = usePathname();
const searchParams = useSearchParams();

const search = async (formData: FormData) => {
  "use server";

  const params = new URLSearchParams(formData);
  redirect(`${pathname}?${params}`, RedirectType.replace);
}

<form action={search} onChange={e => e.currentTarget.requestSubmit()}>
  <input name="query" defaultValue={searchParams.get("query")} />
</form>

<input
  defaultValue={searchParams.get("query")}
  onChange={e => {
    const params = new URLSearchParams({ query: e.currentTarget.value });
    router.replace(`${pathname}?${params}`, { scroll: false });
    router.refresh();
  }}
/>

Neither of these seem to work. The latter, if I don't do router.refresh() I don't see the focus issue, but the data doesn't update either.