{"id":13807687,"url":"https://github.com/adopted-ember-addons/ember-cli-flash","last_synced_at":"2026-02-10T18:09:59.928Z","repository":{"id":26684761,"uuid":"30141536","full_name":"adopted-ember-addons/ember-cli-flash","owner":"adopted-ember-addons","description":"Simple, highly configurable flash messages for ember-cli","archived":false,"fork":false,"pushed_at":"2025-03-05T18:33:52.000Z","size":1297,"stargazers_count":354,"open_issues_count":21,"forks_count":117,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-04-30T10:34:29.946Z","etag":null,"topics":["ember","ember-addon","flash-messages","javascript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/ember-cli-flash","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/adopted-ember-addons.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,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-02-01T09:12:17.000Z","updated_at":"2025-03-05T18:33:09.000Z","dependencies_parsed_at":"2022-06-27T16:00:12.205Z","dependency_job_id":"b54f444e-3d3d-4237-b0d9-d4543fa79380","html_url":"https://github.com/adopted-ember-addons/ember-cli-flash","commit_stats":{"total_commits":303,"total_committers":73,"mean_commits":"4.1506849315068495","dds":0.5379537953795379,"last_synced_commit":"4b4fbac879b3b6fb91b74a92e265d35d6e274a43"},"previous_names":["poteto/ember-cli-flash"],"tags_count":80,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adopted-ember-addons%2Fember-cli-flash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adopted-ember-addons%2Fember-cli-flash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adopted-ember-addons%2Fember-cli-flash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adopted-ember-addons%2Fember-cli-flash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adopted-ember-addons","download_url":"https://codeload.github.com/adopted-ember-addons/ember-cli-flash/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252618454,"owners_count":21777236,"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":["ember","ember-addon","flash-messages","javascript"],"created_at":"2024-08-04T01:01:28.920Z","updated_at":"2026-02-10T18:09:59.922Z","avatar_url":"https://github.com/adopted-ember-addons.png","language":"JavaScript","readme":"# ember-cli-flash\n\n![Download count all time](https://img.shields.io/npm/dt/ember-cli-flash.svg) [![npm version](https://badge.fury.io/js/ember-cli-flash.svg)](http://badge.fury.io/js/ember-cli-flash)\n[![Ember Observer Score](http://emberobserver.com/badges/ember-cli-flash.svg)](http://emberobserver.com/addons/ember-cli-flash)\n\n*Simple, highly configurable flash messages for ember.*\n\nThis ember addon adds a flash message service and component to your app.\n\n## Table of Contents\n\u003c!-- toc --\u003e\n- [ember-cli-flash](#ember-cli-flash)\n  - [Table of Contents](#table-of-contents)\n  - [Installation](#installation)\n  - [Compatibility](#compatibility)\n  - [Usage](#usage)\n    - [Convenience methods (Bootstrap / Foundation alerts)](#convenience-methods-bootstrap--foundation-alerts)\n      - [Bootstrap](#bootstrap)\n      - [Foundation](#foundation)\n    - [Custom messages](#custom-messages)\n      - [Custom messages API](#custom-messages-api)\n    - [Animated example](#animated-example)\n    - [Arbitrary options](#arbitrary-options)\n      - [Example use case](#example-use-case)\n    - [Clearing all messages on screen](#clearing-all-messages-on-screen)\n    - [Returning flash object](#returning-flash-object)\n    - [Finding and removing messages by custom fields](#finding-and-removing-messages-by-custom-fields)\n  - [Service defaults](#service-defaults)\n  - [TypeScript](#typescript)\n    - [Basic Usage](#basic-usage)\n    - [Custom Fields with Generics](#custom-fields-with-generics)\n    - [Typing Dynamically Registered Methods](#typing-dynamically-registered-methods)\n  - [Displaying flash messages](#displaying-flash-messages)\n    - [Custom `close` action](#custom-close-action)\n    - [Styling with Foundation or Bootstrap](#styling-with-foundation-or-bootstrap)\n    - [Styling with user-specified message type class prefix](#styling-with-user-specified-message-type-class-prefix)\n    - [Sort messages by priority](#sort-messages-by-priority)\n    - [Rounded corners (Foundation)](#rounded-corners-foundation)\n    - [Custom flash message component](#custom-flash-message-component)\n  - [Test helpers](#test-helpers)\n  - [Testing](#testing)\n  - [Styling](#styling)\n  - [Upgrading](#upgrading)\n  - [License](#license)\n  - [Contributors](#contributors)\n\u003c!-- tocstop --\u003e\n\n## Installation\n\n```shell\nember install ember-cli-flash\n```\n\n## Compatibility\n\n- Ember.js v4.12 or above\n- Embroider or ember-auto-import v2\n- TypeScript 5.x (optional)\n\nThis addon is tested against the Ember `release`, `beta` and `canary` channels.\n\n## Usage\n\nUsage is very simple. First, add one of the [template examples](#displaying-flash-messages) to your app. Then, inject the `flashMessages` service and use one of its convenience methods:\n\n```typescript\nimport Component from '@glimmer/component';\nimport { service } from '@ember/service';\n\nimport type { FlashMessagesService } from 'ember-cli-flash';\n\nexport default class MyComponent extends Component {\n  @service declare flashMessages: FlashMessagesService;\n}\n```\n\nOr in JavaScript:\n\n```javascript\nimport Component from '@glimmer/component';\nimport { service } from '@ember/service';\n\nexport default class MyComponent extends Component {\n  @service flashMessages;\n}\n```\n\n### Convenience methods (Bootstrap / Foundation alerts)\n\nYou can quickly add flash messages using these methods from the service:\n\n#### Bootstrap\n\n- `.success`\n- `.warning`\n- `.info`\n- `.danger`\n\n#### Foundation\n\n- `.success`\n- `.warning`\n- `.info`\n- `.alert`\n- `.secondary`\n\nThese will add the appropriate classes to the flash message component for styling in Bootstrap or Foundation. For example:\n\n```javascript\n// Bootstrap: the flash message component will have 'alert alert-success' classes\n// Foundation: the flash message component will have 'alert-box success' classes\nthis.flashMessages.success('Success!');\n```\n\nYou can take advantage of Promises, and their `.then` and `.catch` methods. To add a flash message after saving a model (or when it fails):\n\n```javascript\nimport { action } from '@ember/object';\n\n// In your component or controller class...\n@action\nsaveFoo() {\n  this.model\n    .save()\n    .then((res) =\u003e {\n      this.flashMessages.success('Successfully saved!');\n      doSomething(res);\n    })\n    .catch((err) =\u003e {\n      this.flashMessages.danger('Something went wrong!');\n      handleError(err);\n    });\n}\n```\n\nOr with async/await:\n\n```javascript\n@action\nasync saveFoo() {\n  try {\n    const res = await this.model.save();\n    this.flashMessages.success('Successfully saved!');\n    doSomething(res);\n  } catch (err) {\n    this.flashMessages.danger('Something went wrong!');\n    handleError(err);\n  }\n}\n```\n\n### Custom messages\n\nIf the convenience methods don't fit your needs, you can add custom messages with `add`:\n\n```javascript\nthis.flashMessages.add({\n  message: 'Custom message',\n});\n```\n\n#### Custom messages API\n\nYou can also pass in options to custom messages:\n\n```javascript\nthis.flashMessages.add({\n  message: 'I like alpacas',\n  type: 'alpaca',\n  timeout: 500,\n  priority: 200,\n  sticky: true,\n  showProgress: true,\n  extendedTimeout: 500,\n  destroyOnClick: false,\n  onDestroy() {\n    // behavior triggered when flash is destroyed\n  },\n});\n\nthis.flashMessages.success('This is amazing', {\n  timeout: 100,\n  priority: 100,\n  sticky: false,\n  showProgress: true,\n});\n```\n\n- `message: string`\n\n  Required when `preventDuplicates` is enabled. The message that the flash message displays.\n\n- `type?: string`\n\n  Default: `info`\n\n  This is mainly used for styling. The flash message's `type` is set as a class name on the rendered component, together with a prefix. The rendered class name depends on the message type that was passed into the component.\n\n- `timeout?: number`\n\n  Default: `3000`\n\n  Number of milliseconds before a flash message is automatically removed.\n\n- `priority?: number`\n\n  Default: `100`\n\n  Higher priority messages appear before low priority messages. The best practise is to use priority values in multiples of `100` (`100` being the lowest priority). Note that you will need [modify your template](#sort-messages-by-priority) for this work.\n\n- `sticky?: boolean`\n\n  Default: `false`\n\n  By default, flash messages disappear after a certain amount of time. To disable this and make flash messages permanent (they can still be dismissed by click), set `sticky` to true.\n\n- `showProgress?: boolean`\n\n  Default: `false`\n\n  To show a progress bar in the flash message, set this to true.\n\n- `extendedTimeout?: number`\n\n  Default: `0`\n\n  Number of milliseconds before a flash message is removed to add the class 'exiting' to the element.  This can be used to animate the removal of messages with a transition.\n\n- `destroyOnClick?: boolean`\n\n  Default: `true`\n\n  By default, flash messages will be destroyed on click.  Disabling this can be useful if the message supports user interaction.\n\n- `onDestroy: function`\n\n  Default: `undefined`\n\n  A function to be called when the flash message is destroyed.\n\n### Animated example\n\nTo animate messages, set `extendedTimeout` to something higher than zero when adding flash messages:\n\n```javascript\nthis.flashMessages.success('Saved!', {\n  extendedTimeout: 500,\n});\n```\n\nThen animate using CSS transitions, using the `.active` and `.active.exiting` classes.\n\n```scss\n.alert {\n  opacity: 0;\n  position: relative;\n  left: 100px;\n\n  transition: all 700ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n\n  \u0026.active {\n    opacity: 1;\n    left: 0px;\n\n    \u0026.exiting {\n      opacity: 0;\n      left: 100px;\n    }\n  }\n}\n```\n\n### Arbitrary options\n\nYou can also add arbitrary options to messages:\n\n```javascript\nthis.flashMessages.success('Cool story bro', {\n  someOption: 'hello',\n});\n\nthis.flashMessages.add({\n  message: 'hello',\n  type: 'foo',\n  componentName: 'some-component',\n  content: customContent,\n});\n```\n\n#### Example use case\n\nThis makes use of the [component helper](http://emberjs.com/blog/2015/03/27/ember-1-11-0-released.html#toc_component-helper), allowing the template that ultimately renders the flash to be dynamic:\n\n```gjs\nimport Component from '@glimmer/component';\nimport { service } from '@ember/service';\nimport { FlashMessage } from 'ember-cli-flash';\n\nexport default class MyComponent extends Component {\n  @service flashMessages;\n\n  \u003ctemplate\u003e\n    {{#each this.flashMessages.queue as |flash|}}\n      \u003cFlashMessage @flash={{flash}} as |component flash|\u003e\n        {{#if flash.componentName}}\n          {{component flash.componentName content=flash.content}}\n        {{else}}\n          \u003ch6\u003e{{component.flashType}}\u003c/h6\u003e\n          \u003cp\u003e{{flash.message}}\u003c/p\u003e\n        {{/if}}\n      \u003c/FlashMessage\u003e\n    {{/each}}\n  \u003c/template\u003e\n}\n```\n\n### Clearing all messages on screen\n\nIt's best practice to use flash messages sparingly, only when you need to notify the user of something. If you're sending too many messages, and need a way for your users to clear all messages from screen, you can use this method:\n\n```javascript\nthis.flashMessages.clearMessages();\n```\n\n### Returning flash object\n\nThe flash message service is designed to be Fluent, allowing you to chain methods on the service easily. The service should handle most cases but if you want to access the flash object directly, you can use the `getFlashObject` method:\n\n```javascript\nconst flashObject = this.flashMessages.add({\n  message: 'hola',\n  type: 'foo',\n}).getFlashObject();\n```\n\nYou can then manipulate the `flashObject` directly. Note that `getFlashObject` must be the last method in your chain as it returns the flash object directly.\n\n### Finding and removing messages by custom fields\n\nIf you need to track and manage flash messages by a custom identifier (e.g., for notifications that need to be updated or dismissed programmatically), you can use `findBy` and `removeBy`:\n\n```typescript\n// Add a flash with a custom id\nthis.flashMessages.success('Processing...', {\n  id: 'upload-progress',\n});\n\n// Later, find and update or remove it\nconst flash = this.flashMessages.findBy('id', 'upload-progress');\nif (flash) {\n  flash.destroyMessage();\n}\n\n// Or use removeBy for a simpler one-liner\nthis.flashMessages.removeBy('id', 'upload-progress');\n```\n\nThis is useful for scenarios like:\n\n- Dismissing a specific notification when an action completes\n- Replacing a \"loading\" message with a \"success\" message\n- Managing notifications by category or source\n\n## Service defaults\n\nTo customize default values, extend the service and override the `flashMessageDefaults` getter:\n\n```typescript\n// app/services/flash-messages.ts\nimport { FlashMessagesService } from 'ember-cli-flash';\n\nexport default class MyFlashMessages extends FlashMessagesService {\n  get flashMessageDefaults() {\n    return {\n      ...super.flashMessageDefaults,\n      // flash message defaults\n      timeout: 5000,\n      extendedTimeout: 0,\n      priority: 200,\n      sticky: true,\n      showProgress: true,\n\n      // service defaults\n      type: 'alpaca',\n      types: ['alpaca', 'notice', 'foobar'],\n      preventDuplicates: false,\n    };\n  }\n}\n```\n\nOr in JavaScript:\n\n```javascript\n// app/services/flash-messages.js\nimport { FlashMessagesService } from 'ember-cli-flash';\n\nexport default class MyFlashMessages extends FlashMessagesService {\n  get flashMessageDefaults() {\n    return {\n      ...super.flashMessageDefaults,\n      timeout: 5000,\n      extendedTimeout: 0,\n      priority: 200,\n      sticky: true,\n      showProgress: true,\n      type: 'alpaca',\n      types: ['alpaca', 'notice', 'foobar'],\n      preventDuplicates: false,\n    };\n  }\n}\n```\n\nSee the [options](#custom-messages-api) section for information about flash message specific options.\n\n- `type?: string`\n\n  Default: `info`\n\n  When adding a custom message with `add`, if no `type` is specified, this default is used.\n\n- `types?: array`\n\n  Default: `[ 'success', 'info', 'warning', 'danger', 'alert', 'secondary' ]`\n\n  This option lets you specify exactly what types you need, which means in the above example, you can do `this.flashMessages.{alpaca,notice,foobar}`.\n\n- `preventDuplicates?: boolean`\n\n  Default: `false`\n\n  If `true`, only 1 instance of a flash message (based on its `message`) can be added at a time. For example, adding two flash messages with the message `\"Great success!\"` would only add the first instance into the queue, and the second is ignored.\n\n## TypeScript\n\nThis addon is fully typed and supports TypeScript out of the box.\n\n### Basic Usage\n\nThe service and components work seamlessly with TypeScript:\n\n```typescript\nimport Component from '@glimmer/component';\nimport { service } from '@ember/service';\nimport type { FlashMessagesService } from 'ember-cli-flash';\n\nexport default class MyComponent extends Component {\n  @service declare flashMessages: FlashMessagesService;\n\n  showNotification() {\n    this.flashMessages.success('Operation completed!');\n  }\n}\n```\n\n### Custom Fields with Generics\n\nIf your app adds custom fields to flash messages (like `id`, `category`, or `action`), you can get full type safety by using generics:\n\n```typescript\n// app/services/flash-messages.ts\nimport { FlashMessagesService } from 'ember-cli-flash';\n\ninterface CustomFlashFields {\n  id?: string;\n  category?: 'system' | 'user' | 'background';\n  action?: () =\u003e void;\n}\n\nexport default class MyFlashMessages extends FlashMessagesService\u003cCustomFlashFields\u003e {\n  get flashMessageDefaults() {\n    return {\n      ...super.flashMessageDefaults,\n      timeout: 5000,\n    };\n  }\n}\n\n// Don't forget to re-export the type\ndeclare module '@ember/service' {\n  interface Registry {\n    'flash-messages': MyFlashMessages;\n  }\n}\n```\n\nNow you get type checking for your custom fields:\n\n```typescript\n// Type-safe custom fields\nthis.flashMessages.success('File uploaded', {\n  id: 'upload-123',\n  category: 'user',\n});\n\n// TypeScript will catch typos\nthis.flashMessages.success('Oops', {\n  categroy: 'user', // Error: Did you mean 'category'?\n});\n```\n\nCustom fields are also type-safe in templates. The `FlashMessage` component exposes the properly typed flash object with your custom fields:\n\n```gjs\nimport { FlashMessage } from 'ember-cli-flash';\n\n\u003ctemplate\u003e\n  {{#each this.flashMessages.queue as |flash|}}\n    \u003cFlashMessage @flash={{flash}} as |component flash close|\u003e\n      {{flash.message}}\n      {{flash.category}}  {{! ✓ Typed as 'system' | 'user' | 'background' | undefined }}\n      {{#if flash.action}}\n        \u003cbutton type=\"button\" {{on \"click\" flash.action}}\u003eAction\u003c/button\u003e\n      {{/if}}\n    \u003c/FlashMessage\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n### Typing Dynamically Registered Methods\n\nWhen you configure custom `types` in `flashMessageDefaults`, the service dynamically creates convenience methods for each type at runtime. The base class already declares types for the default methods (`success`, `info`, `warning`, `danger`, `alert`, `secondary`), but TypeScript doesn't automatically recognize any custom types you add.\n\nTo get type safety for custom type methods, declare them explicitly in your service subclass:\n\n```typescript\nimport { FlashMessagesService } from 'ember-cli-flash';\nimport type { FlashObjectOptions } from 'ember-cli-flash';\n\ninterface CustomFlashFields {\n  id?: string;\n  category?: string;\n}\n\ntype Options = FlashObjectOptions \u0026 CustomFlashFields;\n\nexport default class MyFlashMessages extends FlashMessagesService\u003cCustomFlashFields\u003e {\n  // Only declare custom types not in the base class\n  // (success, info, warning, danger, alert, secondary are already typed)\n  declare error: (message: string, options?: Options) =\u003e this;\n  declare custom: (message: string, options?: Options) =\u003e this;\n\n  get flashMessageDefaults() {\n    return {\n      ...super.flashMessageDefaults,\n      types: ['error', 'success', 'warning', 'custom'],\n    };\n  }\n}\n```\n\nThis pattern uses TypeScript's `declare` keyword to inform the type system about methods that exist at runtime but aren't defined in the base class types.\n\n## Displaying flash messages\n\nThen, to display somewhere in your app, add this to your component:\n\n```gjs\nimport Component from '@glimmer/component';\nimport { service } from '@ember/service';\nimport { FlashMessage } from 'ember-cli-flash';\n\nexport default class MyComponent extends Component {\n  @service flashMessages;\n\n  \u003ctemplate\u003e\n    {{#each this.flashMessages.queue as |flash|}}\n      \u003cFlashMessage @flash={{flash}} /\u003e\n    {{/each}}\n  \u003c/template\u003e\n}\n```\n\nIt also accepts your own template:\n\n```gjs\nimport Component from '@glimmer/component';\nimport { service } from '@ember/service';\nimport { FlashMessage } from 'ember-cli-flash';\n\nexport default class MyComponent extends Component {\n  @service flashMessages;\n\n  \u003ctemplate\u003e\n    {{#each this.flashMessages.queue as |flash|}}\n      \u003cFlashMessage @flash={{flash}} as |component flash|\u003e\n        \u003ch6\u003e{{component.flashType}}\u003c/h6\u003e\n        \u003cp\u003e{{flash.message}}\u003c/p\u003e\n        {{#if component.showProgressBar}}\n          \u003cdiv class=\"alert-progress\"\u003e\n            \u003cdiv class=\"alert-progressBar\" style={{component.progressDuration}}\u003e\u003c/div\u003e\n          \u003c/div\u003e\n        {{/if}}\n      \u003c/FlashMessage\u003e\n    {{/each}}\n  \u003c/template\u003e\n}\n```\n\n### Custom `close` action\n\nThe `close` action is always passed to the component whether it is used or not. It can be used to implement your own close button, such as an `x` in the top-right corner.\n\nWhen using a custom `close` action, you will want to set `destroyOnClick=false` to override the default (`destroyOnClick=true`). You could do this globally in `flashMessageDefaults`.\n\n```gjs\nimport { on } from '@ember/modifier';\nimport { FlashMessage } from 'ember-cli-flash';\n\n\u003ctemplate\u003e\n  {{#each @flashMessages.queue as |flash|}}\n    \u003cFlashMessage @flash={{flash}} as |component flash close|\u003e\n      {{flash.message}}\n      \u003cspan role=\"button\" {{on \"click\" close}}\u003ex\u003c/span\u003e\n    \u003c/FlashMessage\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n### Styling with Foundation or Bootstrap\n\nBy default, flash messages will have Bootstrap style class names. If you want to use Foundation, simply specify the `messageStyle` on the component:\n\n```gjs\nimport { FlashMessage } from 'ember-cli-flash';\n\n\u003ctemplate\u003e\n  {{#each @flashMessages.queue as |flash|}}\n    \u003cFlashMessage @flash={{flash}} @messageStyle=\"foundation\" /\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n### Styling with user-specified message type class prefix\n\nIf you don't wish to use the class names associated with Bootstrap / Foundation, specify the `messageStylePrefix` on the component. This will override the class name prefixes with your own. For example, `messageStylePrefix='special-alert-'` would create flash messages with the class `special-alert-succcess`\n\n```gjs\nimport { FlashMessage } from 'ember-cli-flash';\n\n\u003ctemplate\u003e\n  {{#each @flashMessages.queue as |flash|}}\n    \u003cFlashMessage @flash={{flash}} @messageStylePrefix=\"special-alert-\" /\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n### Sort messages by priority\n\nTo display messages sorted by priority, use `arrangedQueue` instead of `queue`:\n\n```gjs\nimport { FlashMessage } from 'ember-cli-flash';\n\n\u003ctemplate\u003e\n  {{#each @flashMessages.arrangedQueue as |flash|}}\n    \u003cFlashMessage @flash={{flash}} /\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n### Rounded corners (Foundation)\n\nTo add `radius` or `round` type corners in Foundation:\n\n```gjs\nimport { FlashMessage } from 'ember-cli-flash';\n\n\u003ctemplate\u003e\n  {{#each @flashMessages.arrangedQueue as |flash|}}\n    \u003cFlashMessage @flash={{flash}} @messageStyle=\"foundation\" class=\"radius\" /\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n```gjs\nimport { FlashMessage } from 'ember-cli-flash';\n\n\u003ctemplate\u003e\n  {{#each @flashMessages.arrangedQueue as |flash|}}\n    \u003cFlashMessage @flash={{flash}} @messageStyle=\"foundation\" class=\"round\" /\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n### Custom flash message component\n\nIf the provided component isn't to your liking, you can easily create your own. All you need to do is pass in the `flash` object to that component:\n\n```gjs\nimport CustomComponent from './custom-component';\n\n\u003ctemplate\u003e\n  {{#each @flashMessages.queue as |flash|}}\n    \u003cCustomComponent @flash={{flash}} /\u003e\n  {{/each}}\n\u003c/template\u003e\n```\n\n## Test helpers\n\nThis addon provides helper functions for enabling and disabling flash message timeouts at any time during test runs.\n\nTimeouts are initially disabled during test runs.\n\n- `enableTimeout: () =\u003e void`\n\n  ```js\n  import { enableTimeout } from 'ember-cli-flash/test-support';\n  ```\n\n  Globally enables flash messages removal after `timeout`.\n\n- `disableTimeout: () =\u003e void`\n\n  ```js\n  import { disableTimeout } from 'ember-cli-flash/test-support';\n  ```\n\n  Globally prevents flash messages from being removed after `timeout`.\n\nThese test helpers may be used to enable and disable timeouts granularly, or even for your entire test suite.\n\n```javascript\n// tests/acceptance/foo-page-test.js\n\nimport { module, test } from 'qunit';\nimport { setupApplicationTest } from 'ember-qunit';\nimport { click, visit } from '@ember/test-helpers';\nimport { enableTimeout, disableTimeout } from 'ember-cli-flash/test-support';\n\nmodule('Application | Component | foo-page', function (hooks) {\n  setupApplicationTest(hooks);\n\n  module('with flash message timeout' function (hooks) {\n    hooks.before(function () {\n      // Enable timeout for tests within this module\n      enableTimeout();\n    });\n\n    hooks.after(function () {\n      // Clean up by disabling timeout again\n      disableTimeout();\n    })\n\n    test('flash message is removed after 5 seconds', async function (assert) {\n      assert.expect(1);\n\n      await visit('/');\n\n      await click('.button-that-opens-alert');\n\n      assert.dom('.alert.alert-success').doesNotExist(\n        'Timer was removed due to `timeout: 5_000`'\n      );\n    });\n  });\n});\n```\n\n## Testing\n\nSome example tests below, based on QUnit.\n\nAn example acceptance test:\n\n```javascript\n// tests/acceptance/foo-page-test.js\n\nimport { module, test } from 'qunit';\nimport { setupApplicationTest } from 'ember-qunit';\nimport { click, visit } from '@ember/test-helpers';\n\nmodule('Application | Component | foo-page', function (hooks) {\n  setupApplicationTest(hooks);\n\n  test('flash message is rendered', async function (assert) {\n    assert.expect(1);\n\n    await visit('/');\n\n    await click('.button-that-opens-alert');\n\n    assert.dom('.alert.alert-success').exists({ count: 1 });\n  });\n});\n```\n\nAn example integration test:\n\n```javascript\n// tests/integration/components/x-foo-test.js\n\nimport { module, test } from 'qunit';\nimport { setupRenderingTest } from 'ember-qunit';\nimport { render } from '@ember/test-helpers';\nimport { hbs } from 'ember-cli-htmlbars';\n\nmodule('Integration | Component | x-foo', function (hooks) {\n  setupRenderingTest(hooks);\n\n  hooks.beforeEach(function () {\n    // Register any types you expect to use in this component\n    const typesUsed = ['info', 'warning', 'success'];\n    this.owner.lookup('service:flash-messages').registerTypes(typesUsed);\n  });\n\n  test('it renders', async function (assert) {\n    await render(hbs`\u003cXFoo/\u003e`);\n    // ...\n  });\n});\n```\n\nFor unit tests that require the `flashMessages` service:\n\n```js\nimport { module, test } from 'qunit';\nimport { setupTest } from 'ember-qunit';\n\nmodule('Unit | Route | foo', function (hooks) {\n  setupTest(hooks);\n\n  hooks.beforeEach(function () {\n    const typesUsed = ['info', 'warning', 'success'];\n    this.owner.lookup('service:flash-messages').registerTypes(typesUsed);\n  });\n\n  test('it does the thing', function (assert) {\n    const subject = this.owner.lookup('route:foo');\n    // ...\n  });\n});\n```\n\n## Styling\n\nThis addon is minimal and does not currently ship with a stylesheet. You can style flash messages by targeting the appropriate alert classes in your CSS.\n\n## Upgrading\n\nSee [UPGRADING.md](UPGRADING.md) for migration guides between major versions.\n\n## License\n\n[MIT](LICENSE.md)\n\n## Contributors\n\nWe're grateful to these wonderful contributors who've contributed to `ember-cli-flash`:\n\n[//]: contributor-faces\n\u003ca href=\"https://github.com/poteto\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1390709?v=4\" title=\"poteto\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/sbatson5\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/881981?v=4\" title=\"sbatson5\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/Dhaulagiri\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1672302?v=4\" title=\"Dhaulagiri\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/johno\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1424573?v=4\" title=\"johno\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/rwjblue\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/12637?v=4\" title=\"rwjblue\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/mike-north\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/558005?v=4\" title=\"mike-north\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/makepanic\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1205444?v=4\" title=\"makepanic\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jrjohnson\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/349624?v=4\" title=\"jrjohnson\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/XiphiasUvella\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/95925015?v=4\" title=\"XiphiasUvella\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/st-h\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/5768353?v=4\" title=\"st-h\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/Techn1x\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1049837?v=4\" title=\"Techn1x\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/bgentry\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/114033?v=4\" title=\"bgentry\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/cowboyd\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/4205?v=4\" title=\"cowboyd\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/kmiyashiro\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/71852?v=4\" title=\"kmiyashiro\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/MrChocolatine\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/47531779?v=4\" title=\"MrChocolatine\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/wagenet\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/9835?v=4\" title=\"wagenet\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/abhilashlr\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/5667722?v=4\" title=\"abhilashlr\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jrowlingson\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/3051781?v=4\" title=\"jrowlingson\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jwlawrence\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/488888?v=4\" title=\"jwlawrence\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/sandydoo\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/7572407?v=4\" title=\"sandydoo\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/akisvolanis\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1842448?v=4\" title=\"akisvolanis\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/lxcodes\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/62131?v=4\" title=\"lxcodes\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/aoumiri\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/14907937?v=4\" title=\"aoumiri\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/stukalin\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/9863365?v=4\" title=\"stukalin\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/benmurden\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/213062?v=4\" title=\"benmurden\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/bsclifton\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/4733304?v=4\" title=\"bsclifton\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/caseywatts\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/273653?v=4\" title=\"caseywatts\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/cythrawll\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/99422?v=4\" title=\"cythrawll\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/gilest\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/36919?v=4\" title=\"gilest\" width=\"80\" height=\"80\"\u003e\u003c/a\u003e\n\n[//]: contributor-faces\n","funding_links":[],"categories":["Packages"],"sub_categories":["Real-time"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadopted-ember-addons%2Fember-cli-flash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadopted-ember-addons%2Fember-cli-flash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadopted-ember-addons%2Fember-cli-flash/lists"}