{"id":16506330,"url":"https://github.com/rolemodel/turbo-confirm","last_synced_at":"2025-05-16T07:06:45.160Z","repository":{"id":65659361,"uuid":"596597718","full_name":"RoleModel/turbo-confirm","owner":"RoleModel","description":"The easiest way to add custom confirmation dialog support to Rails apps.","archived":false,"fork":false,"pushed_at":"2025-05-12T22:50:33.000Z","size":478,"stargazers_count":160,"open_issues_count":2,"forks_count":0,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-16T07:06:31.647Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RoleModel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-02-02T14:35:12.000Z","updated_at":"2025-05-12T22:50:08.000Z","dependencies_parsed_at":"2024-03-24T20:24:59.238Z","dependency_job_id":"f7209913-86ac-4b3a-98fd-e4f8b0f26302","html_url":"https://github.com/RoleModel/turbo-confirm","commit_stats":{"total_commits":36,"total_committers":4,"mean_commits":9.0,"dds":"0.38888888888888884","last_synced_commit":"462664254d80d3c6956febb361d5c8117b54f310"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoleModel%2Fturbo-confirm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoleModel%2Fturbo-confirm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoleModel%2Fturbo-confirm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoleModel%2Fturbo-confirm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RoleModel","download_url":"https://codeload.github.com/RoleModel/turbo-confirm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485066,"owners_count":22078767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T15:18:57.162Z","updated_at":"2025-05-16T07:06:40.137Z","avatar_url":"https://github.com/RoleModel.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Turbo Confirm\n\n\u003cdiv\u003e\n  \u003cimg src=\"https://github.com/RoleModel/turbo-confirm/actions/workflows/playwright.yml/badge.svg\" alt=\"CI\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/dw/@rolemodel/turbo-confirm?label=npm\" alt=\"npm\"\u003e\n  \u003cimg src=\"https://data.jsdelivr.com/v1/package/npm/@rolemodel/turbo-confirm/badge?style=rounded\" alt=\"jsDelivr\"\u003e\n\u003c/div\u003e\n\u003cbr/\u003e\n\nA drop-in upgrade for Rails `data-turbo-confirm`.\n\n![title image](title_image.png)\n\n## Installation\n\n```bash\nnpm install @rolemodel/turbo-confirm\n```\n\nor\n\n```bash\nyarn add @rolemodel/turbo-confirm\n```\n\n## Setup\n\nIn your application's JavaScript entry point file. (usually _app/javascript/application.js_)\n\n```js\nimport \"@hotwired/turbo-rails\"\nimport TC from \"@rolemodel/turbo-confirm\"\n\nTC.start()\n```\n\n**note:** `@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 [configuration docs](#configuration) for available options and their default values.\n\n## Usage\n\nTurbo's confirmation interface is exercised most commonly via `button_to` (examples shown in [slim] templating syntax)\n\n```ruby\n  = button_to 'Delete ToDo', todo_path(todo),\n    class: 'btn btn--danger',\n    method: :delete,\n    data: { turbo_confirm: 'Are you sure?' }\n```\n\nor `link_to` with a `data-turbo-method` attribute.\n\n```ruby\n  = link_to 'Delete ToDo', todo_path(todo),\n    class: 'btn btn--danger',\n    data: { \\\n      turbo_method: :delete,\n      turbo_confirm: 'Are you sure?',\n    }\n```\n\nThen add markup to `app/views/layouts/application.html.slim` to render a dialog. See the [Example Template](#example-template) section below.\n\n### Customizing more than just a message\n\n**Turbo-Confirm** supports other custom content beyond a simple message, by setting additional data attributes on the confirmation trigger. Henceforth referred to as _contentSlots_, this feature is both infinitely configurable and completely optional. Out of the box **Turbo-Confirm** supports two:\n\n- **body** activated by a `data-confirm-details` attribute on the confirmation trigger. The attribute's value will be assigned to the element matching the `#confirm-body` selector.\n- **acceptText** activated by a `data-confirm-button` attribute on the confirmation trigger. The attribute's value will be assigned to the element matching the `#confirm-accept` selector (same as the default value of the `acceptSelector` configuration property)\n\nexample usage of default _contentSlots_ via `button_to` in [slim] templating syntax:\n\n```ruby\n  = button_to 'Delete ToDo', todo_path(todo),\n    method: :delete,\n    data: { \\\n      turbo_confirm: 'The following ToDo will be permanently deleted.',\n      confirm_details: simple_format(todo.content),\n      confirm_button: 'Delete ToDo',\n    }\n```\n\n**note:** It's recommended that you have sensible default content already populating each of your configured _contentSlots_ within your app's confirmation dialog template. Such that every confirmation trigger is not required to supply custom content for every _contentSlot_. See our [example template](#example-template) for a good starting point.\n\n### Manual Usage\n\nThough **Turbo-Confirm** was primarily designed to serve as [turbo-rails]' confirmation interface, it may also be invoked directly by application code. In almost the same manner as the native `window.confirm`.  While native confirm pauses execution until the user accepts or declines, **Turbo-Confirm** is [Promise][mdn-promise] based.\n\ne.g.\n\n```js\nimport { TurboConfirm } from \"@rolemodel/turbo-confirm\"\n\nconst tc = new TurboConfirm()\ntc.confirm('Are you sure?').then(response =\u003e { response ? /* accepted */ : /* denied */ })\n```\n\nThe 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.\n\n```js\nimport { TurboConfirm } from \"@rolemodel/turbo-confirm\"\n\nconst tc = new TurboConfirm({ /* Any Custom Configuration */ })\ntc.confirm()\n```\n\n**Turbo-Confirm** has an 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.\n\ne.g.\n\n```js\nimport { TurboConfirm } from \"@rolemodel/turbo-confirm\"\n\nconst tc = new TurboConfirm()\ntc.confirmWithContent({\n  '#confirm-title': 'Are you sure?',\n  '#confirm-accept': 'Do it!'\n}).then(response =\u003e { response ? /* accepted */ : /* denied */ })\n```\n\n**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 [configuration docs](#configuration) for available options and their default values.\n\n### Stimulus Example\n\nWhile 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.\n\nFor those cases, a simple [Stimulus] wrapper around **Turbo-Confirm** is a good solution.\n\ne.g.\n\n```js\nimport { Controller } from \"@hotwired/stimulus\"\nimport { TurboConfirm } from \"@rolemodel/turbo-confirm\"\n\nexport default class extends Controller {\n  #hasAccepted = false\n\n  connect() {\n    this.tc = new TurboConfirm({ /* Any Custom Configuration */ })\n  }\n\n  async perform(event) {\n    if (this.#hasAccepted) {\n      this.#hasAccepted = false\n      return\n    }\n\n    event.preventDefault()\n    event.stopImmediatePropagation()\n\n    if (await this.tc.confirm(event.params.message)) {\n      this.#hasAccepted = true\n      event.target.click()\n    }\n  }\n}\n\n```\n\n```HTML\n\n\u003ca href=\"https://rolemodelsoftware.com\" data-controller=\"confirm\" data-confirm-message-param=\"Do you need custom software?\" data-action=\"confirm#perform\"\u003eClick me\u003c/a\u003e\n\n```\n\n## Configuration\n\n|  Option               | description                                                                                                                                       | default value                       |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |\n| `dialogSelector`      | Global CSS selector used to locate your dialog HTML (an ID selector is recommended)                                                               | `'#confirm'`                        |\n| `activeClass`         | HTML class that causes your dialog element to become visible. (note: you're responsible for defining necessary style rules)                       | `'modal--active'`                   |\n| `acceptSelector`      | CSS selector identifying the button within your dialog HTML which should trigger acceptance of a confirmation challenge                           | `'#confirm-accept'`                 |\n| `denySelector`        | CSS selector identifying the button(s) within your dialog HTML which should trigger rejection of a confirmation challenge                         | `'.confirm-cancel'`                 |\n| `animationDuration`   | approximate number of miliseconds **Turbo-Confirm** should wait for your dialog's CSS to transition to/from a visible state                           | `300`                               |\n| `showConfirmCallback` | a function, called on show with 1 argument (the dialog). The default provides support for native [dialog elements][mdn-dialog]                     | [see below](#default-config-object) |\n| `hideConfirmCallback` | a function, called on accept or reject with 1 argument (the dialog). The default provides support for native [dialog elements][mdn-dialog]         | [see below](#default-config-object) |\n| `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'`                  |\n| `contentSlots`        | an object describing additional customization points. See [contentSlots](#customizing-more-than-just-a-message) for a more detailed description.  | [see below](#default-config-object) |\n\n### Default Config Object\n\n```js\n{\n    dialogSelector: '#confirm',\n    activeClass: 'modal--active',\n    acceptSelector: '#confirm-accept',\n    denySelector: '.confirm-cancel',\n    animationDuration: 300,\n    showConfirmCallback: element =\u003e element.showModal \u0026\u0026 element.showModal(),\n    hideConfirmCallback: element =\u003e element.close \u0026\u0026 element.close(),\n    messageSlotSelector: '#confirm-title',\n    contentSlots: {\n      body: {\n        contentAttribute: 'confirm-details',\n        slotSelector: '#confirm-body'\n      },\n      acceptText: {\n        contentAttribute: 'confirm-button',\n        slotSelector: '#confirm-accept'\n      }\n    }\n  }\n```\n\n## Example Template\n\nBased on the default configuration, the following template is suitable.\n\n```HTML\n  \u003c!-- not visible until a 'modal--active' class is applied to the #confirm element --\u003e\n  \u003cdiv id=\"confirm\" class=\"modal\"\u003e\n    \u003cdiv class=\"modal__backdrop confirm-cancel\"\u003e\u003c/div\u003e\n    \u003cdiv class=\"modal__content\"\u003e\n      \u003ch3 id=\"confirm-title\"\u003eReplaced by `data-turbo-confirm` attribute\u003c/h3\u003e\n      \u003cdiv id=\"confirm-body\"\u003e\n        \u003cp\u003eDefault confirm message.\u003c/p\u003e\n        \u003cp\u003eOptionally replaced by `data-confirm-details` attribute\u003c/p\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"modal-actions\"\u003e\n        \u003cbutton class=\"confirm-cancel\"\u003eCancel\u003c/button\u003e\n        \u003cbutton id=\"confirm-accept\"\u003eYes, I'm Sure\u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n```\n\n### Native Dialogs\n\nIf you're not already using a CSS or style component framework. I suggest checking out [Optics].  Alternatively, the native [dialog][mdn-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`.\n\n**Turbo-Confirm** fully supports the native dialog element, including dismissal via `esc` key.\n\n```HTML\n  \u003c!-- not visible without an [open] attribute, which **Turbo-Confirm** will handle for you --\u003e\n  \u003cdialog id=\"confirm\" class=\"modal\"\u003e\n    \u003cdiv class=\"modal__content\"\u003e\n      \u003ch3 id=\"confirm-title\"\u003eReplaced by `data-turbo-confirm` attribute\u003c/h3\u003e\n      \u003cdiv id=\"confirm-body\"\u003e\n        \u003cp\u003eDefault confirm message.\u003c/p\u003e\n        \u003cp\u003eOptionally replaced by `data-confirm-details` attribute\u003c/p\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"modal-actions\"\u003e\n        \u003cbutton class=\"confirm-cancel\"\u003eCancel\u003c/button\u003e\n        \u003cbutton id=\"confirm-accept\"\u003eYes, I'm Sure\u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/dialog\u003e\n```\n\n## Development\n\nAfter cloning the repository, you'll need to install dependencies by running `yarn install`.\n\nThe test suite can be run with `yarn test`. Or open the [Playwright] GUI application with `yarn test:ui`\n\nFinally, the test app's server can be run on PORT 3000 with `yarn dev`.\n\nEach of these tasks is also accessible via [Rake], if you prefer. Run `rake -T` for details.\n\n## Acknowledgments\n\n**Turbo-Confirm** is [MIT-licensed](LICENSE), open-source software from [RoleModel Software][rms].\n\n[RoleModel Software][rms] 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.\n\n[slim]: https://github.com/slim-template/slim\n[turbo-rails]: https://github.com/hotwired/turbo-rails/\n[Stimulus]: https://github.com/hotwired/stimulus/\n[mdn-promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\n[mdn-dialog]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog/\n[Optics]: https://github.com/RoleModel/optics/\n[Playwright]: https://playwright.dev/\n[Rake]: https://github.com/ruby/rake/\n[rms]: https://rolemodelsoftware.com/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frolemodel%2Fturbo-confirm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frolemodel%2Fturbo-confirm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frolemodel%2Fturbo-confirm/lists"}