{"id":15015937,"url":"https://github.com/mainmatter/ember-promise-modals","last_synced_at":"2025-08-21T23:33:02.623Z","repository":{"id":37799902,"uuid":"205395469","full_name":"mainmatter/ember-promise-modals","owner":"mainmatter","description":"The easy solution for rendering and handling modals in Ember.js apps. Promised.","archived":false,"fork":false,"pushed_at":"2024-04-14T10:13:20.000Z","size":7577,"stargazers_count":30,"open_issues_count":16,"forks_count":14,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-04-14T20:04:33.390Z","etag":null,"topics":["emberjs","emberjs-addon","modals","promises"],"latest_commit_sha":null,"homepage":"https://ember-promise-modals.com","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/mainmatter.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","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}},"created_at":"2019-08-30T14:11:56.000Z","updated_at":"2024-04-15T22:28:31.717Z","dependencies_parsed_at":"2023-09-28T20:49:25.079Z","dependency_job_id":"aef0ba49-ec3e-45de-9e74-7b0e4e911376","html_url":"https://github.com/mainmatter/ember-promise-modals","commit_stats":{"total_commits":714,"total_committers":18,"mean_commits":"39.666666666666664","dds":0.6176470588235294,"last_synced_commit":"e9f3e5ee968c37eb84e5a5ec29e898f971e4e13b"},"previous_names":["simplabs/ember-promise-modals"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainmatter%2Fember-promise-modals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainmatter%2Fember-promise-modals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainmatter%2Fember-promise-modals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainmatter%2Fember-promise-modals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mainmatter","download_url":"https://codeload.github.com/mainmatter/ember-promise-modals/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230542288,"owners_count":18242332,"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":["emberjs","emberjs-addon","modals","promises"],"created_at":"2024-09-24T19:48:10.963Z","updated_at":"2025-08-21T23:33:02.614Z","avatar_url":"https://github.com/mainmatter.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"./packages/test-app/public/ember-promise-modals-logo.svg\" role=\"presentation\" alt=\"\" width=\"600\" height=\"400\" /\u003e\u003c/p\u003e\n\n# ember-promise-modals\n\nThe better way to handle modals in your Ember.js apps.\n\n\u003e [!NOTE]\n\u003e ember-promise-modals was written and is maintained by [Mainmatter](https://mainmatter.com) and contributors.\n\u003e We offer consulting, training, and team augmentation for Ember.js – check out our [website](https://mainmatter.com/ember-consulting/) to learn more!\n\n## Compatibility\n\n- Ember.js v3.28 or above\n- Embroider or ember-auto-import v2\n\n## Installation\n\n```\nember install ember-promise-modals\n```\n\n## Usage\n\nTo use EPM in your project, add the target for the modals to your `application.hbs`:\n\n```hbs\n\u003cEpmModalContainer /\u003e\n```\n\nThen you can inject the `modals` [service](https://guides.emberjs.com/release/services/#toc_accessing-services) wherever you need and call its `open` method with a component class to render it as a modal.\n\n```js\nimport { inject as service } from '@ember/service';\nimport ConfirmationModal from 'my-app/components/confirmation-modal';\n\nexport default class extends Component {\n  @service modals;\n\n  @action\n  async handleOpenModal() {\n    let modal = this.modals.open(ConfirmationModal);\n\n    // the instance acts as a promise that resolves with anything passed to the @close function\n    modal.then(results =\u003e {\n      // do something with the data\n    });\n\n    // so does `await`ing it!\n    let results = await modal;\n\n    // you can also close the modal from outside\n    modal.close();\n  }\n}\n```\n\n```hbs\n\u003cbutton type='button' {{on 'click' this.handleOpenModal}}\u003e\n  Click Me!\n\u003c/button\u003e\n```\n\n### Passing data to the rendered component\n\nYou can pass custom data into your rendered template like so:\n\n```js\nthis.modals.open(FilePreviewModal, {\n  fileUrl: this.fileUrl,\n});\n```\n\nAll passed attributes can be accessed from the passed-in `data` object:\n\n```hbs\n\u003c!-- components/file-preview.hbs --\u003e\n\u003cimg src={{@data.fileUrl}} /\u003e\n```\n\n```js\n// components/file-preview.js\nthis.args.data.fileUrl; // or this.data.fileUrl in classic components\n```\n\n**NOTE:** By default, a `close` method is passed in your rendered component, in\norder to trigger the \"close modal\" action. It can be called like so:\n\n```hbs\n\u003c!-- components/file-preview.hbs --\u003e\n\u003cbutton type='button' {{on 'click' (fn @close results)}}\u003eClose\u003c/button\u003e\n```\n\n```js\n// components/file-preview.js\nthis.args.close(results); // or this.close() in classic components\n```\n\n### Routable modals using the template helper\n\nThis addon comes with a `{{open-modal}}` template helper which can be used to trigger modals from any templates. It accepts the similar arguments as the `open` method. It can be used to open a modal in a route, closing it automatically when navigating elsewhere.\n\n```hbs\n{{open-modal this.ConfirmationModalComponent (hash fileUrl=this.fileUrl) close=(fn this.save results)}}\n```\n\nPositional arguments mimick the `open()` method on the service:\n\n- `componentClass`: An imported component class of the modal to render\n- `data`: Pass additional context to the modal,\n- `options`: Pass additional options to the modal\n\nNamed arguments:\n\n- `close` is called asynchronously with the data returned by the modals `@close` action when it is closed\n\n## Animation\n\nThis addon uses CSS animations. You can either replace the\n[styles of this addon](./addon/styles/ember-promise-modals.css) with your own\nor adjust the defaults using CSS custom properties in your `:root{}`\ndeclaration or in the CSS of any parent container of `\u003cEpmModalContainer /\u003e`.\n\nAvailable properties and their defaults can be found in the `:root {}` block inside the addons css.\n\nBy default, the animations are dropped when `prefers-reduced-motion` is\ndetected.\n\n### Custom animations\n\nTo override the animation for a specific modal, an `options` object containing\na custom `className` can be handed to the `.open()` method.\n\n```js\nthis.modals.open(\n  FilePreviwModal,\n  {\n    fileUrl: this.fileUrl,\n  },\n  {\n    // custom class, see below for example\n    className: 'custom-modal',\n    // optional: name the animation triggered by the custom css class\n    //           animations ending in \"-out\" are detected by default!\n    //           You most likely do not have to do this unless you absolutely\n    //           can't have an animation ending in '-out'\n    animationKeyframesOutName: 'custom-animation-name-out',\n    // optional: a hook that is called when the closing animation of\n    //           the modal (so not the backdrop) has finished.\n    onAnimationModalOutEnd: () =\u003e {},\n  },\n);\n```\n\n```css\n.custom-modal {\n  animation: custom-animation-in 0.5s;\n  opacity: 1;\n  transform: translate(0, 0);\n}\n\n/* \n  The `.epm-out` class is added to the parent of the modal when the modal \n  should be closed, which triggers the animation\n*/\n.custom-modal.epm-out {\n  animation: custom-animation-name-out 0.2s; /* default out animation is 2s */\n  opacity: 0;\n  transform: translate(0, 100%);\n}\n\n/* \n  animation name has to end in \"-out\" to be detected by the custom animationend \n  event handler \n*/\n@keyframes custom-animation-name-out {\n  0% {\n    opacity: 1;\n    transform: translate(0, 0);\n  }\n  100% {\n    opacity: 0;\n    transform: translate(0, 100%);\n  }\n}\n```\n\nThe CSS animations which are applied by the custom CSS class _must_ end in\n`-out` to make the animations trigger the modal removal.\n\n#### Examples\n\nExamples for custom animations and how to apply them can be found in the addon's\ndummy application.\n\nSee [the application.js controller](./packages/test-app/app/controllers/application.js)\nfor how the modals are opened in your JavaScript actions and look at\n[app.css](./packages/test-app/app/styles/app.css) for the style definition of these\ncustom animations.\n\n## Accessibility\n\nUser can press the \u003ckbd\u003eEsc\u003c/kbd\u003e key to close the modal.\n\nEPM uses [focus-trap](https://github.com/davidtheclark/focus-trap) internally\nin order to handle user focus.\n\nEPM will ensure to [focus the first \"tabbable element\" by default](https://www.w3.org/TR/wai-aria-practices-1.1/#dialog_modal).\nIf no focusable element is present, focus will be applied on the currently\nvisible auto-generated container for the current modal.\n\nFocus Trap can be configured both on the `modals` service, and the individual\nmodal level when calling `this.modals.open()`. Global and local options are used\nin that order, which means that local config take precedence.\n\nTo set global Focus Trap config that all modals inherit, override the default\n`Modals` service by extending it, place it to `app/services/modals.js`, then\nuse the `focusTrapOptions` property:\n\n```js\nimport BaseModalsService from 'ember-promise-modals/services/modals';\n\nexport default class ModalsService extends BaseModalsService {\n  focusTrapOptions = {\n    clickOutsideDeactivates: false,\n  };\n}\n```\n\nExample for local Focus Trap option, when opening a specific modal:\n\n```js\nthis.modals.open(\n  FilePreviewModal,\n  { fileUrl: this.fileUrl },\n  {\n    focusTrapOptions: {\n      clickOutsideDeactivates: false,\n    },\n  },\n);\n```\n\nTo disable Focus Trap completely, set `focusTrapOptions` to `null` on the\n`modals` service:\n\n```js\nimport BaseModalsService from 'ember-promise-modals/services/modals';\n\nexport default class ModalsService extends BaseModalsService {\n  focusTrapOptions = null;\n}\n```\n\nOr when opening a modal:\n\n```js\nthis.modals.open(\n  FilePreviewModal,\n  { fileUrl: this.fileUrl },\n  {\n    focusTrapOptions: null,\n  },\n);\n```\n\n⚠️ _We strongly advise against doing this. This will in most cases worsen the\naccessibility of modals for your users. Be very careful._\n\n## Testing\n\nThis addon provides a test helper function that reduces the timing for the CSS transitions to near zero to speed up your tests.\n\n```js\nimport { setupPromiseModals } from 'ember-promise-modals/test-support';\n\nmodule('Application | ...', function (hooks) {\n  // ...\n  setupPromiseModals(hooks);\n  // ...\n});\n```\n\n## Migration guide\n\nSee the [Migration](MIGRATION.md) guide for details:\n\n- From 0.x.x to 1.x.x about the replacement of ember-animated powered animations with CSS-based animations.\n- From v4.x.x to v5.x.x about the removal of the PostCSS process.\n\n## Contributing\n\nSee the [Contributing](CONTRIBUTING.md) guide for details.\n\n## License\n\nember-promise-modals is developed by and © Mainmatter GmbH and contributors. It\nis released under the [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmainmatter%2Fember-promise-modals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmainmatter%2Fember-promise-modals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmainmatter%2Fember-promise-modals/lists"}