Custom Confirm Dialog For Turbo and Rails
Tags: rails, hotwire, webdev, javascript
Published: 2024-05-14 09:00:00

This article was originally published on [Rails Designer](https://railsdesigner.com/custom-confirm-dialog/).

---

With Turbo it is pretty straightforward to customize the browser's confirmation dialog. [Rails Designer](https://railsdesigner.com/) has just released a new set of utilities that includes a custom confirmation dialog packed with **three great-looking themes**.

**Light Theme**

This is the default “theme”. Works well for most apps.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7hor7gwhych7kyf3l2j.jpg)

**Light Glass Theme**

Similar to the light theme, but with a glass-like effect. Subtle, but looks cool with really visual apps.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unbj7x3jn7vg0p570er0.jpg)

**Dark Theme**

I like to use dark elements like these in an otherwise light application.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtn7ldln33yestcbikac.jpg)

Besides the message, you can also set the “confirm” and the “cancel” button labels. This is how you would use it in your Rails app:

```ruby
button_to "Delete…",
filters_path(filter),
  method: :delete,
  data: {
    turbo_method: "delete",
    turbo_confirm: "Really delete this filter?",
    turbo_confirm_confirm_label: "Yes, delete",
    turbo_confirm_cancel_label: "No, go back",
  }
```

(Note: [Rails Designer](https://railsdesigner.com/)'s version also accepts the `theme` attribute).

---


Adding your own custom dialog is just a few lines of code. First customize Turbo Drive's confirmation handling, using its [`Turbo.setConfirmMethod`](https://turbo.hotwired.dev/reference/drive#turbo.setconfirmmethod) with a modal that resolves actions based on user clicks on "commit" or "cancel" buttons. The `once: true` means they each are configured for a single use.

```js
// app/javascript/application.js
Turbo.setConfirmMethod((message, element) => {
  const dialog = insertConfirmModal(message, element);

  return new Promise((resolve) => {
    dialog.querySelector("[data-behavior='cancel']").addEventListener("click", () => {
      dialog.remove();

      resolve(false);
    }, { once: true })
    dialog.querySelector("[data-behavior='commit']").addEventListener("click", () => {
      dialog.remove();

      resolve(true);
    }, { once: true })
  })
})
```

Then the `insertConfirmModal()` function could look a bit like this.

```js
// app/javascript/application.js
function insertConfirmModal(message, element) {
content = `
  <div id="confirm-modal">
    ${message}
    <button data-behavior="commit">Confirm</button>
    <button data-behavior="cancel">Cancel</button>
  </div>
`

  document.body.insertAdjacentHTML('beforeend', content);
  document.activeElement.blur();

  return document.getElementById("confirm-modal");
}
```

It inserts a confirmation modal (`#confirm-modal`) into the webpage and removes focus from the currently active element, returning this newly created modal element.

Of course it needs a bit of styling, but as you can see from above examples you can style it however you want!