'Link tag not triggering onSubmit when clicking on the form's submit button

For some reason when I wrap my Link tag around my form's submit button it doesn't trigger the onSubmit() function. What am I doing wrong?

    import { Link } from "react-router-dom";
  <form className="gift-search" onSubmit={onSubmit}>
      <div>
        <input
          type="text"
          name="giftSearch"
          placeholder="Search for any gifts"
          onChange={onChange}
        />
      </div>
    <Link to={{ pathname: `/category/${giftSearchState}` }}>
          <button type="submit" className="search-btn">
            Search
          </button>
        </Link>
   </form>


Solution 1:[1]

I would navigate programmatically using useNavigate() :


const navigate = useNavigate();

const onSubmit = (e) => {
  e.preventDefault();
  navigate(`/category/${giftSearchState}`);
}

...

<form className="gift-search" onSubmit={onSubmit}>
  <div>
    <input
      type="text"
      name="giftSearch"
      placeholder="Search for any gifts"
      onChange={onChange}
    />
  </div>
  <button type="submit" className="search-btn">
    Search
  </button>
</form>

Solution 2:[2]

There is nothing wrong with your code.

Internally, the react-router-dom Link component will render an html link <a> with the children (in this case your button).

You can see the Link source code here.

But the problem is not that, I created a sandbox example using the button inside a <a> and inside a <Link>, and you can check for yourself that when you have a button inside a <a/>, if the button has the type=submit, then the form onSubmit will be called.

The problem is following: The Link component has its own onClick function internally and it calls the preventDefault to allow only the back button click, you can see at this line

So, what is happening is:

Your button is clicked, and the event is captured and not prevented, then the Link captures the event and call the preventDefault so it will never reach your onSubmit form function.

In the codesand, I let a console.log in the button onClick so you can see that the event.button is equal to 0

The react-router-dom source code is really interesting, I recommend you to take a look :)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Monstar
Solution 2 Thomaz Capra