Skip to content

Toasts ​

Toast notifications are typically used to display messages to the user after an action has been performed. They are non-blocking notifications that can be dismissed by the user.

Basic usage ​

To display a toast, you can use one of the methods exposed by the useToasts composable.

vue
<script setup>
  import useToasts from '@leaflink/stash-vue/useToasts';

  const toasts = useToasts();
</script>

<template>
  <Button @click="toasts.info('hey there 👋')">Show toast</Button>
</template>

Or with various severity levels:

template
<Button secondary color="blue" class="mr-3" @click="toasts.success('Success toast')">Success</Button>
<Button secondary color="blue" class="mr-3" @click="toasts.info('Info toast')">Info</Button>
<Button secondary color="red" class="mr-3" @click="toasts.error('Error toast')">Error</Button>
<Button secondary color="red" @click="toasts.warning('Warning toast')">Warning</Button>

Installation ​

You don't have to do anything to start using toasts. Toasts are actually enabled as a separate plugin within Stash named ToastsPlugin. The plugin is installed automatically when using @leaflink/stash-vue.

You should be able to call useToasts() right away after installing and running app.use('@leaflink/stash-vue').

If you need to set toast options:

ts
import stash from '@leaflink/stash-vue';

app.use(stash, {
  toasts: { 
    mountNodeId: 'some-id', 
    mountNodeClass: 'some-class', 
  }, 
});

If you don't need or want it to be loaded you can opt out:

ts
import stash from '@leaflink/stash-vue';

app.use(stash, {
  toasts: false, 
});

If you opt out from loading it automatically from Stash, you can also load it manually:

ts
import { createApp } from 'vue';
import ToastsPlugin from '@leaflink/stash-vue/ToastsPlugin';

const app = createApp(App);

app.use(ToastsPlugin); 

The ToastsPlugin can receive options as the second argument to app.use().

ts
import { createApp } from 'vue';
import ToastsPlugin from '@leaflink/stash-vue/ToastsPlugin';

const app = createApp(App);

app.use(ToastsPlugin, { mountNodeClass: 'my-class' }); 

Manually ​

Alternatively, if you don't want to use ToastsPlugin, you can manually render the <Toasts /> component wherever you want in your application. Ideally, there should be only one instance of this component per app.

vue
<script setup lang="ts">
  import Toasts from '@leaflink/stash-vue/Toasts.vue';
</script>

<template>
  <Toasts />
</template>

Advanced usage ​

To display a more complex structured content such as a rich text, you can pass down a render function or a template string as the content of the toast.

vue
<Button @click="toasts.success(() => h(MyToastContent))">
  Show toast
</Button>

See this section for more information on how to provide HTML content to the toast.

Testing ​

In order to ensure that toasts are being displayed during component tests, you need to use the stash plugin.

ts
import { render } from '@testing-library/vue';
import stash from '@leaflink/stash-vue';
import userEvent from '@testing-library/user-event';

it('shows a toast when button is clicked', async () => {
  render(Component, {
    global: {
      plugins: [stash],
    },
  });

  const user = userEvent.setup();
  await user.click(screen.getByRole('button'));

  expect(await screen.findByText('I am a toast!')).toBeInTheDocument();
});

Cleaning up ​

Because toast notifications are displayed asynchronously and removed from the DOM after a timeout, you want to ensure that toasts are being cleared after every test. If you're using @leaflink/dom-testing-utils this is extremely easy.

In setup-env.ts, just add the following line:

ts
import '@leaflink/dom-testing-utils/setup-env';

If you're not using that library, you can also add this explicitly.

ts
import { config } from '@vue/test-utils';
import stash from '@leaflink/stash-vue';
import useToasts from '@leaflink/stash-vue/useToasts';

config.global.plugins = [stash];

afterEach(() => {
  useToasts().removeAll();
});

If you only need to do this for a single test for some reason, you can also do it in the test itself:

ts
import { render } from '@testing-library/vue';
import stash from '@leaflink/stash-vue';
import useToasts from '@leaflink/stash-vue/useToasts';
import userEvent from '@testing-library/user-event';

afterEach(() => {
  useToasts().removeAll();
});

it('shows a toast when button is clicked', async () => {
  render(Component, {
    global: {
      plugins: [stash],
    },
  });

  const user = userEvent.setup();
  await user.click(screen.getByRole('button'));

  expect(await screen.findByText('I am a toast!')).toBeInTheDocument();
});