til

How to handle multiple submit buttons in a form

typescriptjavascriptbrowsers

Normally, we use forms with only one submit button, but because they are just inputs, you can define multiple of them.

The key to knowing which button was clicked or submitted when you hit enter is to give them all the same name.

interface AcceptRejectSubmitEvent extends SubmitEvent {
  readonly submitter: HTMLButtonElement;
}

export default function App() {
  const [chosenButton, setChosenButton] = React.useState<string>(null);

  const onSubmit = (
    e: React.SyntheticEvent<HTMLFormElement, AcceptRejectSubmitEvent>
  ) => {
    e.preventDefault();

    const submitter = e.nativeEvent.submitter;
    setChosenButton(submitter.value);
  };

  return (
    <div>
      <form onSubmit={onSubmit}>
        <p>I agree with the terms ...</p>

        <div>
          <label htmlFor="name">Email: </label>

          <input type="email" name="email" id="email" required />
        </div>

        <div className="buttons" style={{ display: "flex" }}>
          <button
            type="submit"
            name="commit"
            value="reject"
            style={{ order: 1 }}
          >
            Reject
          </button>

          <button type="submit" name="commit" value="accept">
            Accept
          </button>
        </div>

        {chosenButton && <output>You choose {chosenButton}</output>}
      </form>
    </div>
  );
}

Examine the following lines of code:

  1. When you press enter, the first button in the DOM is the one specified by e.nativeEvent.submitter. I used order to change the order of appearance, but it wasn't taken into account.
  2. You must use the SubmitEvent method. Because submitter is of type HTMLElement by default, we extend the SubmitEvent to override the submitter type to avoid casting.

If you use action and method to handle the submit action on the server, you will get the attribute commit with the value accept or reject.

You can play with it here