Undoing deletes with Phoenix LiveView and view components

02 Mar 2025

Andrew Timberlake has writen a great post on how to undo deletes using Phoenix Liveview.

Destructive actions need to be handled carefully, so that a user doesn’t inadvertently lose important data. The most common solution in a web app is to provide a confirmation step before the action is applied, but providing an undo option makes deletion frictionless and safe. This pattern can also be seen in the ability to undo a send operation in email apps.

This matches my own experience while working on SaaS products: confirmation messages are not great. People don’t usually read them and, even if they do, sometimes they proceed by mistake and then the action cannot be undone.

Once this happens and you notice that you have deleted the wrong thing there is an extremely bad feeling. Suddenly you feel stupid and the application seems scary.

Allowing users to undo actions is a much better alternative. There can still be a confirmation phase in which you explain what’s going to happen to the user. Still, once the user has performed the action, there is short period of time when they can undo it.

The main tool for providing this kind of undoable action in Phoenix LiveView is the view model.

For each record, you need to know if it is selected or deleted, and in the case of the deleted items that can be undone, some information to support the undo is needed

The view model is a layer that sits between the view and the model and exposes models in a way that can be easily managed and presented in the view. In this particular case Andrew created a DeletableItemView that wraps the original item and adds a few extra fields to manage deletes.

The main piece of additional information is the delete_ref, which references the message that will perform the deletion. This message is sent after 5 seconds and deletes the record. If the user undoes the action, the message is canceled and the record is never deleted.

Unfortunately relying only on Erlang processes is not reliable enough. But as Andrew shows, we can use Oban to perform the deletion in a much more reliable way by using a background job.

The problem with this approach is that the action is not actually performed until the message is received. If the user moves away from this live view, or refreshes the page, then the deletion will not be performed.