---
title: "Toast"
description: "A succinct message that is displayed temporarily."
canonical_url: "https://vinicunca.dev/akar/components/toast"
---
# Toast

> A succinct message that is displayed temporarily.

```vue [index.vue]
<script setup lang="ts">
import { ToastAction, ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from 'akar'
import { ref } from 'vue'
import './styles.css'

const open = ref(false)
const eventDateRef = ref(new Date())
const timerRef = ref(0)

function oneWeekAway() {
  const now = new Date()
  const inOneWeek = now.setDate(now.getDate() + 7)
  return new Date(inOneWeek)
}

function prettyDate(date: Date) {
  return new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'short' }).format(date)
}

function handleClick() {
  open.value = false
  window.clearTimeout(timerRef.value)
  timerRef.value = window.setTimeout(() => {
    eventDateRef.value = oneWeekAway()
    open.value = true
  }, 100)
}
</script>

<template>
  <div class="akar-demo akar-demo-Toast">
    <ToastProvider>
        <button
          class="Button large grass"
          @click="handleClick"
        >
          Add to calendar
        </button>

        <ToastRoot
          v-model:open="open"
          class="ToastRoot"
        >
          <ToastTitle class="ToastTitle">
            Scheduled: Catch up
          </ToastTitle>
          <ToastDescription as-child>
            <time
              class="ToastDescription"
              :dateTime="eventDateRef.toISOString()"
            >
              {{ prettyDate(eventDateRef) }}
            </time>
          </ToastDescription>
          <ToastAction
            class="ToastAction"
            as-child
            alt-text="Goto schedule to undo"
          >
            <button class="Button small green">
              Undo
            </button>
          </ToastAction>
        </ToastRoot>
        <ToastViewport class="ToastViewport" />
      </ToastProvider>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/green.css';
@import '../_colors/mauve.css';
@import '../_colors/slate.css';
@import '../_colors/grass.css';

@scope (.akar-demo-Toast) {
/* reset */
button {
  all: unset;
}

.ToastViewport {
  --viewport-padding: 25px;
  position: fixed;
  bottom: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  padding: var(--viewport-padding);
  gap: 10px;
  width: 390px;
  max-width: 100vw;
  margin: 0;
  list-style: none;
  z-index: 2147483647;
  outline: none;
}

.ToastRoot {
  background-color: white;
  border-radius: 6px;
  box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
  padding: 15px;
  display: grid;
  grid-template-areas: 'title action' 'description action';
  grid-template-columns: auto max-content;
  column-gap: 15px;
  align-items: center;
}
.ToastRoot[data-state='open'] {
  animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1);
}
.ToastRoot[data-state='closed'] {
  animation: hide 100ms ease-in;
}
.ToastRoot[data-swipe='move'] {
  transform: translateX(var(--akar-toast-swipe-move-x));
}
.ToastRoot[data-swipe='cancel'] {
  transform: translateX(0);
  transition: transform 200ms ease-out;
}
.ToastRoot[data-swipe='end'] {
  animation: swipeOut 100ms ease-out;
}

@keyframes hide {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes slideIn {
  from {
    transform: translateX(calc(100% + var(--viewport-padding)));
  }
  to {
    transform: translateX(0);
  }
}

@keyframes swipeOut {
  from {
    transform: translateX(var(--akar-toast-swipe-end-x));
  }
  to {
    transform: translateX(calc(100% + var(--viewport-padding)));
  }
}

.ToastTitle {
  grid-area: title;
  margin-bottom: 5px;
  font-weight: 500;
  color: var(--slate-12);
  font-size: 15px;
}

.ToastDescription {
  grid-area: description;
  margin: 0;
  color: var(--slate-11);
  font-size: 13px;
  line-height: 1.3;
}

.ToastAction {
  grid-area: action;
}

.Button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  font-weight: 500;
}
.Button.small {
  font-size: 12px;
  padding: 0 10px;
  line-height: 25px;
  height: 25px;
}
.Button.large {
  font-size: 15px;
  padding: 0 15px;
  line-height: 35px;
  height: 35px;
}
.Button.grass {
  background-color: white;
  color: var(--grass-11);
  box-shadow: 0 2px 10px var(--black-a7);
}
.Button.grass:hover {
  background-color: var(--mauve-3);
}
.Button.grass:focus {
  box-shadow: 0 0 0 2px black;
}
.Button.green {
  background-color: var(--green-2);
  color: var(--green-11);
  box-shadow: inset 0 0 0 1px var(--green-7);
}
.Button.green:hover {
  box-shadow: inset 0 0 0 1px var(--green-8);
}
.Button.green:focus {
  box-shadow: 0 0 0 2px var(--green-8);
}
}
```

- Automatically closes.
- Pauses closing on hover, focus and window blur.
- Supports hotkey to jump to toast viewport.
- Supports closing via swipe gesture.
- Exposes CSS variables for swipe gesture animations.
- Can be controlled or uncontrolled.

## Installation

Install the component from your command line.

```bash [pnpm]
pnpm add akar
```

```bash [yarn]
yarn add akar
```

```bash [npm]
npm install akar
```

```bash [bun]
bun add akar
```

## Anatomy

Import the component.

```vue
<script setup lang="ts">
import { ToastAction, ToastClose, ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from 'akar';
</script>

<template>
  <ToastProvider>
    <ToastRoot>
      <ToastTitle />
      <ToastDescription />
      <ToastAction />
      <ToastClose />
    </ToastRoot>

    <ToastViewport />
  </ToastProvider>
</template>
```

## API Reference

### Provider

The provider that wraps your toasts and toast viewport. It usually wraps the application.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `disableSwipe` | `false` | `boolean` | Whether to disable the ability to swipe to close the toast. |
| `duration` | `5000` | `number` | Time in milliseconds that each toast should remain visible for. |
| `label` | `"Notification"` | `string` | An author-localized label for each toast. Used to help screen reader users<br>associate the interruption with a toast. |
| `swipeDirection` | `"right"` | `"right" \| "left" \| "down" \| "up"` | Direction of pointer swipe that should close the toast. |
| `swipeThreshold` | `50` | `number` | Distance in pixels that the swipe must pass before a close is triggered. |

[ToastProvider.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastProvider.vue)

### Viewport

The fixed area where toasts appear. Users can jump to the viewport by pressing a hotkey. It is up to you to ensure the discoverability of the hotkey for keyboard users.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"ol"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `hotkey` | `["F8"]` | `string[]` | The keys to use as the keyboard shortcut that will move focus to the toast viewport. |
| `label` | `"Notifications ({hotkey})"` | `string \| ((hotkey: string) => string)` | An author-localized label for the toast viewport to provide context for screen reader users<br>when navigating page landmarks. The available `{hotkey}` placeholder will be replaced for you.<br>Alternatively, you can pass in a custom function to generate the label. |

[ToastViewport.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastViewport.vue)

### Root

The toast that automatically closes. It should not be held open to [acquire a user response](https://vinicunca.dev/akar/components/toast#action).

> [!NOTE]
> 
> Defer mounting with `forceMount` / [`Presence`](https://vinicunca.dev/akar/utilities/presence). See the [animation guide](https://vinicunca.dev/akar/guides/animation).

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"li"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `defaultOpen` | `true` | `boolean` | The open state of the dialog when it is initially rendered. Use when you do not need to control its open state. |
| `duration` |  | `number` | Time in milliseconds that toast should remain visible for. Overrides value<br>given to `ToastProvider`. |
| `forceMount` |  | `boolean` | Used to force mounting when more control is needed. Useful when<br>controlling animation with Vue animation libraries. |
| `open` |  | `boolean` | The controlled open state of the dialog. Can be bind as `v-model:open`. |
| `type` | `"foreground"` | `"foreground" \| "background"` | Control the sensitivity of the toast for accessibility purposes.<br><br>For toasts that are the result of a user action, choose `foreground`. Toasts generated from background tasks should use `background`. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `escapeKeyDown` | `event: KeyboardEvent` | Event handler called when the escape key is down. It can be prevented by calling `event.preventDefault`. |
| `pause` |  | Event handler called when the dismiss timer is paused. This occurs when the pointer is moved over the viewport, the viewport is focused or when the window is blurred. |
| `resume` |  | Event handler called when the dismiss timer is resumed. This occurs when the pointer is moved away from the viewport, the viewport is blurred or when the window is focused. |
| `swipeCancel` | `event: SwipeEvent` | Event handler called when swipe interaction is cancelled. It can be prevented by calling `event.preventDefault`. |
| `swipeEnd` | `event: SwipeEvent` | Event handler called at the end of a swipe interaction. It can be prevented by calling `event.preventDefault`. |
| `swipeMove` | `event: SwipeEvent` | Event handler called during a swipe interaction. It can be prevented by calling `event.preventDefault`. |
| `swipeStart` | `event: SwipeEvent` | Event handler called when starting a swipe interaction. It can be prevented by calling `event.preventDefault`. |
| `update:open` | `value: boolean` | Event handler called when the open state changes |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `open` | `boolean` | Current open state |
| `remaining` | `number` | Remaining time (in ms) |
| `duration` | `number` | Total time the toast will remain visible for (in ms) |

[ToastRoot.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastRoot.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "open" \\| "closed" |
| `[data-swipe]` | "start" \\| "move" \\| "cancel" \\| "end" |
| `[data-swipe-direction]` | "up" \\| "down" \\| "left" \\| "right" |

| CSS variable | Description |
| --- | --- |
| `--akar-toast-swipe-move-x` | The offset position of the toast when horizontally swiping |
| `--akar-toast-swipe-move-y` | The offset position of the toast when vertically swiping |
| `--akar-toast-swipe-end-x` | The offset end position of the toast after horizontally swiping |
| `--akar-toast-swipe-end-y` | The offset end position of the toast after vertically swiping |

### Portal

When used, portals the content part into the `body`.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `defer` |  | `boolean` | Defer the resolving of a Teleport target until other parts of the<br>application have mounted (requires Vue 3.5.0+)<br><br>[reference](https://vuejs.org/guide/built-ins/teleport.html#deferred-teleport) |
| `disabled` |  | `boolean` | Disable teleport and render the component inline<br><br>[reference](https://vuejs.org/guide/built-ins/teleport.html#disabling-teleport) |
| `forceMount` |  | `boolean` | Used to force mounting when more control is needed. Useful when<br>controlling animation with Vue animation libraries. |
| `to` |  | `string \| HTMLElement` | Vue native teleport component prop `:to`<br><br>[reference](https://vuejs.org/guide/built-ins/teleport.html#basic-usage) |

[ToastPortal.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastPortal.vue)

### Title

An optional title for the toast

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[ToastTitle.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastTitle.vue)

### Description

The toast message.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[ToastDescription.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastDescription.vue)

### Action

An action that is safe to ignore to ensure users are not expected to complete tasks with unexpected side effects as a result of a [time limit](https://www.w3.org/TR/UNDERSTANDING-WCAG20/time-limits-required-behaviors.html).

When obtaining a user response is necessary, portal an ["AlertDialog"](https://vinicunca.dev/akar/components/alert-dialog) styled as a toast into the viewport instead.

By default, clicking `ToastAction` dismisses the toast. Set `closeOnClick` to `false` when the action should run while keeping the toast visible.

```vue
<template>
  <ToastAction
    alt-text="Retry sending the message"
    :close-on-click="false"
    @click="retry"
  >
    Retry
  </ToastAction>
</template>
```

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `altText*` |  | `string` | A short description for an alternate way to carry out the action. For screen reader users<br>who will not be able to navigate to the button easily/quickly. |
| `as` | `"button"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `closeOnClick` | `true` | `boolean` | Whether the action should close the toast when clicked. |

[ToastAction.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastAction.vue)

### Close

A button that allows users to dismiss the toast before its duration has elapsed.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"button"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[ToastClose.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast/ToastClose.vue)

## Examples

### Custom hotkey

Override the default hotkey using the `event.code` value for each key from [keycode.info](https://keycode.info/).

```vue
<template>
  <ToastProvider>
    ...
    <ToastViewport :hotkey="['altKey', 'KeyT']" />
  </ToastProvider>
</template>
```

### Custom duration

Customise the duration of a toast to override the provider value.

```vue
<template>
  <ToastRoot :duration="3000">
    <ToastDescription>Saved!</ToastDescription>
  </ToastRoot>
</template>
```

### Duplicate toasts

When a toast must appear every time a user clicks a button, use state to render multiple instances of the same toast (see below). Alternatively, you can abstract the parts to create your own [imperative API](https://vinicunca.dev/akar/components/toast#imperative-api).

```vue
<template>
  <div>
    <form @submit="count++">
      ...
      <button>save</button>
    </form>

    <ToastRoot v-for="(_, index) in count" :key="index">
      <ToastDescription>Saved!</ToastDescription>
    </ToastRoot>
  </div>
</template>
```

### Animating swipe gesture

Combine `--akar-toast-swipe-move-[x|y]` and `--akar-toast-swipe-end-[x|y]` CSS variables with `data-swipe="[start|move|cancel|end]"` attributes to animate a swipe to close gesture. Here's an example:

```vue
<template>
  <ToastProvider swipe-direction="right">
    <ToastRoot class="ToastRoot">
      ...
    </ToastRoot>
    <ToastViewport />
  </ToastProvider>
</template>
```

```css
/* styles.css */
.ToastRoot[data-swipe='move'] {
  transform: translateX(var(--akar-toast-swipe-move-x));
}
.ToastRoot[data-swipe='cancel'] {
  transform: translateX(0);
  transition: transform 200ms ease-out;
}
.ToastRoot[data-swipe='end'] {
  animation: slideRight 100ms ease-out;
}

@keyframes slideRight {
  from {
    transform: translateX(var(--akar-toast-swipe-end-x));
  }
  to {
    transform: translateX(100%);
  }
}
```

## Accessibility

Adheres to the [`aria-live` requirements](https://www.w3.org/TR/wai-aria/#aria-live).

### Sensitivity

Control the sensitivity of the toast for screen readers using the `type` prop.

For toasts that are the result of a user action, choose `foreground`. Toasts generated from background tasks should use `background`.

#### Foreground

Foreground toasts are announced immediately. Assistive technologies may choose to clear previously queued messages when a foreground toast appears. Try to avoid stacking distinct foreground toasts at the same time.

#### Background

Background toasts are announced at the next graceful opportunity, for example, when the screen reader has finished reading its current sentence. They do not clear queued messages so overusing them can be perceived as a laggy user experience for screen reader users when used in response to a user interaction.

```vue
<template>
  <ToastRoot type="foreground">
    <ToastDescription>File removed successfully.</ToastDescription>
    <ToastClose>Dismiss</ToastClose>
  </ToastRoot>

  <ToastRoot type="background">
    <ToastDescription>We've just released Akar 2.0.</ToastDescription>
    <ToastClose>Dismiss</ToastClose>
  </ToastRoot>
</template>
```

### Alternative action

Use the `altText` prop on the `Action` to instruct an alternative way of actioning the toast to screen reader users.

You can direct the user to a permanent place in your application where they can action it or implement your own custom hotkey logic. If implementing the latter, use `foreground` type to announce immediately and increase the duration to give the user ample time.

```vue
<template>
  <ToastRoot type="background">
    <ToastTitle>Upgrade Available!</ToastTitle>
    <ToastDescription>We've just released Akar 2.0.</ToastDescription>
    <ToastAction alt-text="Goto account settings to upgrade">
      Upgrade
    </ToastAction>
    <ToastClose>Dismiss</ToastClose>
  </ToastRoot>

  <ToastRoot type="foreground" :duration="10000">
    <ToastDescription>File removed successfully.</ToastDescription>
    <ToastAction alt-text="Undo (Alt+U)">
      Undo <kbd>Alt</kbd>+<kbd>U</kbd>
    </ToastAction>
    <ToastClose>Dismiss</ToastClose>
  </ToastRoot>
</template>
```

### Close icon button

When providing an icon (or font icon), remember to label it correctly for screen reader users.

```vue
<template>
  <ToastRoot type="foreground">
    <ToastDescription>Saved!</ToastDescription>
    <ToastClose aria-label="Close">
      <span aria-hidden="true">×
    </ToastClose>
  </ToastRoot>
</template>
```

### Keyboard Interactions

| Key | Description |
| --- | --- |
| <kbd>F8</kbd> | Focuses toasts viewport. |
| <kbd>Tab</kbd> | Moves focus to the next focusable element. |
| <kbd>Shift + Tab</kbd> | Moves focus to the previous focusable element. |
| <kbd>Space</kbd> |  When focus is on a `ToastAction`, closes the toast when `closeOnClick` is `true`. When focus is on `ToastClose`, closes the toast.  |
| <kbd>Enter</kbd> |  When focus is on a `ToastAction`, closes the toast when `closeOnClick` is `true`. When focus is on `ToastClose`, closes the toast.  |
| <kbd>Esc</kbd> |  When focus is on a `Toast`, closes the toast  |

## Custom APIs

### Abstract parts

Create your own API by abstracting the primitive parts into your own component.

#### Usage

```vue
<script setup lang="ts">
import Toast from './your-toast.vue';
</script>

<template>
  <Toast
    title="Upgrade available"
    content="We've just released Radix 3.0!"
  >
    <button @click="handleUpgrade">
      Upgrade
    </button>
  </Toast>
</template>
```

#### Implementation

```vue
// your-toast.vue
<script setup lang="ts">
import { ToastAction, ToastClose, ToastDescription, ToastRoot, ToastTitle } from 'akar';

defineProps<{
  title: string;
  content: string;
}>();
</script>

<template>
  <ToastRoot>
    <ToastTitle v-if="title">
      {{ title }}
    </ToastTitle>
    <ToastDescription v-if="content">
      {{ content }}
    </ToastDescription>
    <ToastAction
      as-child
      alt-text="toast"
    >
      <slot />
    </ToastAction>
    <ToastClose aria-label="Close">
      <span aria-hidden="true">×
      </span>
    </ToastClose>
  </ToastRoot>
</template>
```

### Imperative API

Create your own imperative API to allow [toast duplication](https://vinicunca.dev/akar/components/toast#duplicate-toasts) if preferred.

#### Usage

```vue
<script setup lang="ts">
import Toast from './your-toast.vue';

const savedRef = ref<InstanceType<typeof Toast>>();
</script>

<template>
  <div>
    <form @submit="savedRef.publish()">
      ...
    </form>
    <Toast ref="savedRef">
      Saved successfully!
    </Toast>
  </div>
</template>
```

#### Implementation

```vue
// your-toast.vue
<script setup lang="ts">
import { ToastClose, ToastDescription, ToastRoot, ToastTitle } from 'akar';
import { ref } from 'vue';

const count = ref(0);

function publish() {
  count.value++;
}

defineExpose({
  publish
});
</script>

<template>
  <ToastRoot
    v-for="index in count"
    :key="index"
  >
    <ToastDescription>
      <slot />
    </ToastDescription>
    <ToastClose>Dismiss</ToastClose>
  </ToastRoot>
</template>
```

---

- [ARIA](https://www.w3.org/TR/wai-aria/#aria-live)
- [GitHub](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Toast)
- [npm](https://www.npmjs.com/package/akar)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
