Search code examples
reactjsmantine

Mantine Form TextInput won't maintain focus when input is wrapped in another component


I came across an issue which I'm not sure is a bug or just my lack of understanding React.

The problem is that when I'm using Mantine's useForm inputProps on a TextInput inside of a component which is defined inside of another component, the input won't maintain focus and prevents me from typing into the input.

App.tsx

export const App: FC<{ name: string }> = ({ name }) => {
  const form = useForm({
    initialValues: {
      test: '',
    },
  });

  return (
    <MantineProvider>
      <div>
        <h1>Hello {name}!</h1>
        <p>Start editing to see some magic happen :)</p>
        <Test inputProps={form.getInputProps('test')} />
      </div>
    </MantineProvider>
  );
};

Test.tsx

export default function Test({ inputProps }) {
  const Wrap = () => {
    return <TextInput placeholder="Test..." {...inputProps} />;
  };

  // Doesn't work...
  return <Wrap />;

  // Works...
  // return <TextInput placeholder="Test..." {...inputProps} />;
}

This can be seen here: https://stackblitz.com/edit/stackblitz-starters-dptysf?file=src%2FApp.tsx

To reproduce, attempt to focus the input. To see the working version, comment out the "not working" line and uncomment the "working" line.

My expectation is that both returning <Wrap> as well as just returning the <TextInput> directly from <Test> would result in the same exact thing, but that doesn't appear to be the case.


Solution

  • This was happening because React is creating a new reference to the inner "Wrap" component every time "Test" is rerendered. React is unmounting the old instance of "Wrap" and remounting a new instance, which is messing with the state of the TextInput.

    Declaring "Wrap" outside of the "Test" component resolves the issue.

    const Wrap = ({ inputProps }) => {
      return <TextInput placeholder="Test..." {...inputProps} />;
    };
    
    export default function Test({ inputProps }) {
      return <Wrap inputProps={inputProps}/>;
    }