mantine icon indicating copy to clipboard operation
mantine copied to clipboard

`useFocusWithin` calls outdated `onFocus` and `onBlur` handlers

Open kurgm opened this issue 2 months ago • 2 comments

Dependencies check up

  • [x] I have verified that I use latest version of all @mantine/* packages

What version of @mantine/* packages do you have in package.json?

8.3.9

What package has an issue?

@mantine/hooks

What framework do you use?

create-react-app (CRA)

In which browsers you can reproduce the issue?

All

Describe the bug

The useFocusWithin hook calls outdated callback handlers that capture stale state values from the initial render.

Reproduction

In the following code, the ref returned by useFocusWithin is attached to a form element:

import { useFocusWithin } from "@mantine/hooks";
import { useState } from "react";

function MyComponent() {
  const [focusCount, setFocusCount] = useState(0);
  const [blurCount, setBlurCount] = useState(0);

  const { focused, ref } = useFocusWithin({
    onFocus: () => {
      console.log("focused!");
      setFocusCount(focusCount + 1);
    },
    onBlur: () => {
      console.log("blurred!");
      setBlurCount(blurCount + 1);
    },
  });
  return (
    <div>
      <p>focusCount = {focusCount}</p>
      <p>blurCount = {blurCount}</p>
      <p>focused = {focused ? "true" : "false"}</p>
      <form ref={ref}>
        <input type="text" placeholder="inside form" />
      </form>
      <button>outside form</button>
    </div>
  );
}

Expected behavior

When repeatedly moving focus between the input (inside the form) and the button (outside the form), the corresponding value of focusCount or blurCount should increment each time the focus changes.

Actual behavior

focusCount and blurCount never exceed 1, even though "focused!" and "blurred!" are logged to the console every time the focus changes. This suggests that useFocusWithin continues to call the onFocus and onBlur handlers from the initial render, which captured the initial values of focusCount and blurCount (both 0).

If possible, include a link to a codesandbox with a minimal reproduction

https://codesandbox.io/p/devbox/mantine-react-template-forked-jccfsr

Possible fix

In the source code of useFocusWithin, there are places where previousNode.current is read, but it is never updated. Assigning previousNode.current = node within callbackRef may resolve this issue (though I haven't verified this yet).

Self-service

  • [ ] I would be willing to implement a fix for this issue

kurgm avatar Nov 30 '25 13:11 kurgm

Sure @hassanzadeh-mj you are welcome to submit a PR with a fix

rtivital avatar Dec 09 '25 06:12 rtivital