npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@rolemodel/turbo-confirm

v2.2.0

Published

Drop-in upgrade for Rails' data-turbo-confirm feature to support custom HTML dialogs.

Downloads

4,916

Readme

Turbo Confirm

A drop-in upgrade for Rails data-turbo-confirm.

title image

Installation

bin/importmap pin @rolemodel/turbo-confirm

or

yarn add @rolemodel/turbo-confirm

or

npm install @rolemodel/turbo-confirm

Setup

In your application's JavaScript entry point file. (usually app/javascript/application.js)

import "@hotwired/turbo-rails"
import TC from "@rolemodel/turbo-confirm"

TC.start()

Then add your custom dialog markup to your application's layout. See the Example Template below for a good starting point that works with the default configuration.

[!IMPORTANT] @hotwired/turbo-rails must be imported prior to calling the start function. This is so Turbo-Confirm can coordinate with Turbo regarding confirmation handling. The start function is also where you may override default behavior by passing a configuration object. See the configuration table for available properties and their default values.

Basic Usage

Turbo's confirmation interface is exercised most commonly via button_to (examples shown in slim templating syntax)

  = button_to 'Delete ToDo', todo_path(todo),
    class: 'btn btn--danger',
    method: :delete,
    data: { turbo_confirm: 'Are you sure?' }

or link_to with a data-turbo-method attribute.

  = link_to 'Delete ToDo', todo_path(todo),
    class: 'btn btn--danger',
    data: { \
      turbo_method: :delete,
      turbo_confirm: 'Are you sure?',
    }

Dynamic Content Slots

By setting additional, optional data attributes on the confirmation trigger, Turbo-Confirm adapts dynamically in different contexts.

Out of the box, Turbo-Confirm ships with two optional ContentSlots:

  • body activated by a data-confirm-details attribute on the confirmation trigger. The attribute's value will be assigned to the element matching the selector #confirm-body
  • acceptText activated by a data-confirm-button attribute on the confirmation trigger. The attribute's value will be assigned to the element matching the selector #confirm-accept

example in slim templating syntax:

  = button_to 'Delete ToDo', todo_path(todo),
    method: :delete,
    data: { \
      turbo_confirm: 'The following ToDo will be permanently deleted.',
      confirm_details: simple_format(todo.content),
      confirm_button: 'Delete ToDo',
    }

See also this discussion, for instructions on defining additional dynamic ContentSlots.

[!TIP] we recommend populating your dialog template with sensible default content and only triggering the dynamic ContentSlots where necessary. See the example template for reference.

Manual Usage

Turbo-Confirm can also serve as a general replacement for the native window.confirm function. Though it returns a Promise instead of pausing execution.

e.g.

import { TurboConfirm } from "@rolemodel/turbo-confirm"

const tc = new TurboConfirm()
tc.confirm('Are you sure?').then(response => { response ? /* accepted */ : /* denied */ })

The message itself is optional as well. Simply call confirm() with no arguments and your dialog's default content will be displayed un-altered. e.g.

import { TurboConfirm } from "@rolemodel/turbo-confirm"

const tc = new TurboConfirm({ /* Any Custom Configuration */ })
tc.confirm()

Turbo-Confirm has one additional public method, confirmWithContent that expects a contentMap object where the keys are content slot selectors and the values are the content you want displayed in each selected element.

e.g.

import { TurboConfirm } from "@rolemodel/turbo-confirm"

const tc = new TurboConfirm()
tc.confirmWithContent({
  '#confirm-title': 'Are you sure?',
  '#confirm-accept': 'Do it!'
}).then(response => { response ? /* accepted */ : /* denied */ })

[!NOTE] The TurboConfirm constructor creates a brand new instance that will not share configuration with the one Turbo-Rails is using. For that reason, a config object may be passed into the TurboConfirm constructor. See the configuration table for available properties and their default values.

Stimulus Wrapper

While Turbo will invoke Turbo-Confirm for you in the case of a form submission (like button_to) or form link (like link_to with a data-turbo-method), in the case of a regular link or a button that does not submit a form, you're on your own. But Turbo-Confirm can help!

For those cases, a simple Stimulus wrapper around Turbo-Confirm is a good solution.

e.g.

import { Controller } from "@hotwired/stimulus"
import { TurboConfirm } from "@rolemodel/turbo-confirm"

export default class extends Controller {
  #hasAccepted = false

  connect() {
    this.tc = new TurboConfirm({ /* Any Custom Configuration */ })
  }

  async perform(event) {
    if (this.#hasAccepted) {
      this.#hasAccepted = false
      return
    }

    event.preventDefault()
    event.stopImmediatePropagation()

    if (await this.tc.confirm(event.params.message)) {
      this.#hasAccepted = true
      event.target.click()
    }
  }
}

<a href="https://rolemodelsoftware.com" data-controller="confirm" data-confirm-message-param="Do you need custom software?" data-action="confirm#perform">Click me</a>

Configuration

| Property | Description | Default Value | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- | | dialogSelector | Global CSS selector used to locate your dialog HTML (an ID selector is recommended) | '#confirm' | | activeClass | HTML class that causes your dialog element to become visible. (note: you're responsible for defining necessary style rules) | 'modal--active' | | acceptSelector | CSS selector identifying the button within your dialog HTML which should trigger acceptance of a confirmation challenge | '#confirm-accept' | | denySelector | CSS selector identifying the button(s) within your dialog HTML which should trigger rejection of a confirmation challenge | '.confirm-cancel' | | animationDuration | approximate number of miliseconds Turbo-Confirm should wait for your dialog's CSS to transition to/from a visible state | 300 | | showConfirmCallback | a function, called on show with 1 argument (the dialog). The default provides support for native dialog elements | see below | | hideConfirmCallback | a function, called on accept or reject with 1 argument (the dialog). The default provides support for native dialog elements | see below | | messageSlotSelector | CSS selector of the element within your dialog HTML where the value of data-turbo-confirm (or supplied message) should be rendered | '#confirm-title' | | contentSlots | an object describing additional customization points. See contentSlots for a more detailed description. | see below |

Default Config Object

{
    dialogSelector: '#confirm',
    activeClass: 'modal--active',
    acceptSelector: '#confirm-accept',
    denySelector: '.confirm-cancel',
    animationDuration: 300,
    showConfirmCallback: element => element.showModal && element.showModal(),
    hideConfirmCallback: element => element.close && element.close(),
    messageSlotSelector: '#confirm-title',
    contentSlots: {
      body: {
        contentAttribute: 'confirm-details',
        slotSelector: '#confirm-body'
      },
      acceptText: {
        contentAttribute: 'confirm-button',
        slotSelector: '#confirm-accept'
      }
    }
  }

Inert Attribute

The inert attribute makes elements non-interactive. This is useful in preventing hidden elements from obscuring the user's intended click target, which is a common issue when you have multiple hidden dialogs on the page.

Turbo-Confirm will automatically add an inert attribute to your confirmation element when it becomes hidden and then remove it once it becomes visible again. We also recommend that you include this attribute in your template. See the example below for reference.

Example Template

Based on the default configuration, the following template is suitable.

  <!-- not visible until a 'modal--active' class is applied to the #confirm element -->
  <div id="confirm" class="modal" inert>
    <div class="modal__backdrop confirm-cancel"></div>
    <div class="modal__content">
      <h3 id="confirm-title">Replaced by `data-turbo-confirm` attribute</h3>
      <div id="confirm-body">
        <p>Default confirm message.</p>
        <p>Optionally replaced by `data-confirm-details` attribute</p>
      </div>
      <div class="modal-actions">
        <button class="confirm-cancel">Cancel</button>
        <button id="confirm-accept">Yes, I'm Sure</button>
      </div>
    </div>
  </div>

Native Dialogs

If you're not already using a CSS or style component framework. I suggest checking out Optics. Alternatively, the native dialog element is fully supported by modern browsers and removes much of the styling burden that would otherwise be required to emulate such behavior with only a div.

Turbo-Confirm fully supports the native dialog element, including dismissal via esc key.

  <dialog id="confirm" class="modal" inert>
    <div class="modal__content">
      <h3 id="confirm-title">Replaced by `data-turbo-confirm` attribute</h3>
      <div id="confirm-body">
        <p>Default confirm message.</p>
        <p>Optionally replaced by `data-confirm-details` attribute</p>
      </div>
      <div class="modal-actions">
        <button class="confirm-cancel">Cancel</button>
        <button id="confirm-accept">Yes, I'm Sure</button>
      </div>
    </div>
  </dialog>

Development

After cloning the repository, you'll need to install dependencies by running yarn install.

The test suite can be run with yarn test. Or open the Playwright GUI application with yarn test:ui

Finally, the test app's server can be run on PORT 3000 with yarn dev.

Each of these tasks is also accessible via Rake, if you prefer. Run rake -T for details.

Acknowledgments

Turbo-Confirm is MIT-licensed, open-source software from RoleModel Software.

RoleModel Software is a world-class, collaborative software development team dedicated to delivering the highest quality custom web and mobile software solutions while cultivating a work environment where community, family, learning, and mentoring flourish.