guide 009

How to create one form with many actions in Remix

We have been in the middle of a migration at Crunchy Data from an express app to Remix, and boy have there been plenty of technical tidbits I am excited to write about on here. Last week I had a really interesting one I couldn't wait to write about. So let's do it.

In our app we have an integrated set of support pages. Behind the scenes it is run through Helpscout, but in app we allow teams to create, reply, and close support tickets without needing to jump to an email client.

The interesting implementation I came across appeared as I was migrating our open ticket page.

Ticket Detail View

As you can see the page consists of three core areas.

  • Reply form.

  • Ticket details

  • Message Thread

What we are digging into is the first one.

One form multiple actions

The reply form is unique in that it is responsible for 3 potential actions that can be taken on it.

  • If no message exists you can close the ticket using the secondary button.

  • Once you have typed a message, that secondary button changes allowing you to submit that message as a new reply on the ticket thread and close the ticket at the same time.

  • Or, you can just submit the message and leave the ticket open.

Three very different outcomes that all live within that single form.

Obviously we could isolate the close ticket button somewhere else in the UI so that the form only has two actions, buuut we like the UX of having all actions that effect the state of the ticket tied together in a single place.

Thankfully, the solution for allowing that is a html feature that has been around since..well I am pretty sure forever. So, let's knock out the core solution and then we can dig into some extra ✨ that makes it nicer to work with in Remix and Typescript.

The core solution

This is all you really need to know that makes this whole thing tick.

In html a button is allowed to have a name and a value. This name and value combo is only appended to the form data if it is the button that was used to submit the form.

That's it. That is the solution, and here is what that shakes down to in our Remix codebase:

New Message