Toast

AkarGitHub
A succinct message to provide information or feedback to the user.

Usage

Use the useToast composable to display a toast in your application.

<script setup lang="ts">
import { useToast } from '#imports'

const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide:calendar-days'
  })
}
</script>

<template>
  <PButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide:plus"
    @click="addToCalendar"
  />
</template>
Make sure to wrap your app with the App component which uses our Toaster component which uses the AToastProvider component from Akar.
You can check the App component toaster prop to see how to configure the Toaster globally.

Title

Pass a title field to the toast.add method to display a title.

<script setup lang="ts">
import { useToast } from '#imports';

const props = defineProps<{
  title: string;
}>();

const toast = useToast();

function showToast() {
  toast.add(props);
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Description

Pass a description field to the toast.add method to display a description.

<script setup lang="ts">
import { useToast } from '#imports';

const props = defineProps<{
  title: string;
  description: string;
}>();

const toast = useToast();

function showToast() {
  toast.add(props);
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Icon

Pass an icon field to the toast.add method to display an Icon.

<script setup lang="ts">
import { useToast } from '#imports';

const props = defineProps<{
  icon: string;
}>();

const toast = useToast();

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: props.icon,
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Avatar

Pass an avatar field to the toast.add method to display an Avatar.

<script setup lang="ts">
import type { PAvatarProps } from 'pohon-ui';
import { useToast } from '#imports';

const props = defineProps<{
  avatar: PAvatarProps;
}>();

const toast = useToast();

function showToast() {
  toast.add({
    title: 'User invited',
    description: 'praburangki was invited to the team.',
    avatar: props.avatar,
  });
}
</script>

<template>
  <PButton
    label="Invite user"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Color

Pass a color field to the toast.add method to change the color of the Toast.

<script setup lang="ts">
import type { PToastProps } from 'pohon-ui';
import { useToast } from '#imports';

const props = defineProps<{
  color: PToastProps['color'];
}>();

const toast = useToast();

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: 'i-lucide:wifi',
    color: props.color,
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Close

Pass a close field to customize or hide the close Button (with false value).

<script setup lang="ts">
import { useToast } from '#imports';

const toast = useToast();

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: 'i-lucide:wifi',
    close: {
      color: 'primary',
      variant: 'outline',
      class: 'rounded-full',
    },
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Close Icon

Pass a closeIcon field to customize the close button Icon. Default to i-lucide:x.

<script setup lang="ts">
import { useToast } from '#imports';

const props = defineProps<{
  closeIcon: string;
}>();

const toast = useToast();

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    closeIcon: props.closeIcon,
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>
You can customize this icon globally in your app.config.ts under pohon.icons.close key.
You can customize this icon globally in your vite.config.ts under pohon.icons.close key.

Actions

Pass an actions field to add some Button actions to the Toast.

<script setup lang="ts">
import { useToast } from '#imports';

const props = defineProps<{
  description: string;
}>();

const toast = useToast();

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: props.description,
    actions: [{
      icon: 'i-lucide:refresh-cw',
      label: 'Retry',
      color: 'neutral',
      variant: 'outline',
      onClick: (e) => {
        e?.stopPropagation();
      },
    }],
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Progress

Pass a progress field to customize or hide the Progress bar (with false value).

The Progress bar inherits the Toast color by default, but you can override it using the progress.color field.
<script setup lang="ts">
import { useToast } from '#imports';

const toast = useToast();

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: 'i-lucide:wifi',
    progress: false,
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Orientation

Pass an orientation field to the toast.add method to change the orientation of the Toast.

<script setup lang="ts">
import { useToast } from '#imports';

const props = defineProps<{
  orientation: 'horizontal' | 'vertical';
}>();

const toast = useToast();

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    orientation: props.orientation,
    actions: [{
      icon: 'i-lucide:refresh-cw',
      label: 'Retry',
      color: 'neutral',
      variant: 'outline',
      onClick: (e) => {
        e?.stopPropagation();
      },
    }],
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

Examples

Pohon UI provides an App component that wraps your app to provide global configurations.

Change global position

Change the toaster.position prop on the App component to change the position of the toasts.

app.vue
<script setup lang="ts">
const toaster = { position: 'bottom-right' };
</script>

<template>
  <PApp :toaster="toaster">
    <NuxtPage />
  </PApp>
</template>
<script setup lang="ts">
import { useToast } from '#imports'

const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide:calendar-days'
  })
}
</script>

<template>
  <PButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide:plus"
    @click="addToCalendar"
  />
</template>
In this example, we use the AppConfig to configure the position prop of the Toaster component globally.

Change global duration

Change the toaster.duration prop on the App component to change the duration of the toasts.

app.vue
<script setup lang="ts">
const toaster = { duration: 5000 };
</script>

<template>
  <PApp :toaster="toaster">
    <NuxtPage />
  </PApp>
</template>
<script setup lang="ts">
import { useToast } from '#imports'

const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide:calendar-days'
  })
}
</script>

<template>
  <PButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide:plus"
    @click="addToCalendar"
  />
</template>
In this example, we use the AppConfig to configure the duration prop of the Toaster component globally.

Change global max

Change the toaster.max prop on the App component to change the max number of toasts displayed at once.

app.vue
<script setup lang="ts">
const toaster = { max: 3 };
</script>

<template>
  <PApp :toaster="toaster">
    <NuxtPage />
  </PApp>
</template>
<script setup lang="ts">
import { useToast } from '#imports'

const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide:calendar-days'
  })
}
</script>

<template>
  <PButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide:plus"
    @click="addToCalendar"
  />
</template>
In this example, we use the AppConfig to configure the max prop of the Toaster component globally.

Stacked toasts

Set the toaster.expand prop to false on the App component to display stacked toasts (inspired by Sonner).

app.vue
<script setup lang="ts">
const toaster = { expand: true };
</script>

<template>
  <PApp :toaster="toaster">
    <NuxtPage />
  </PApp>
</template>
You can hover over the toasts to expand them. This will also pause the timer of the toasts.
<script setup lang="ts">
import { useToast } from '#imports'

const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide:calendar-days'
  })
}
</script>

<template>
  <PButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide:plus"
    @click="addToCalendar"
  />
</template>
In this example, we use the AppConfig to configure the expand prop of the Toaster component globally.

With callback

Pass an onUpdate:open field to execute a callback when the toast is closed (either by expiration or user dismissal).

<script setup lang="ts">
const toast = useToast();

function showToast() {
  toast.add({
    'title': 'Uploading file...',
    'description': 'Your file is being uploaded.',
    'icon': 'i-lucide-cloud-upload',
    'duration': 3000,
    'onUpdate:open': function (open: boolean) {
      if (!open) {
        toast.add({
          title: 'File uploaded!',
          description: 'Your file has been successfully uploaded.',
          icon: 'i-lucide-check',
          color: 'success',
        });
      }
    },
  });
}
</script>

<template>
  <PButton
    label="Show toast"
    color="neutral"
    variant="outline"
    @click="showToast"
  />
</template>

API

Props

Prop Default Type
as'li'any

The element or component this component should render as.

orientation'vertical'"vertical" | "horizontal"

The orientation between the content and the actions.

type"background" | "foreground"

Control the sensitivity of the toast for accessibility purposes.

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

durationnumber

Time in milliseconds that toast should remain visible for. Overrides value given to AToastProvider.

titlestring | VNode<RendererNode, RendererElement, { [key: string]: any; }> | (): VNode<RendererNode, RendererElement, { [key: string]: any; }>
descriptionstring | VNode<RendererNode, RendererElement, { [key: string]: any; }> | (): VNode<RendererNode, RendererElement, { [key: string]: any; }>
iconstring | object
avatarPAvatarProps
color'primary'"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
closeIconappConfig.pohon.icons.closestring | object

The icon displayed in the close button.

actionsPButtonProps[]

Display a list of actions:

  • under the title and description when orientation is vertical
  • next to the close button when orientation is horizontal{ size: 'xs' }
closetrueboolean

Display a close button to dismiss the toast. { size: 'md', color: 'neutral', variant: 'link' }

progresstrueboolean

Display a progress bar showing the toast's remaining duration. { size: 'sm' }

defaultOpenboolean

The open state of the dialog when it is initially rendered. Use when you do not need to control its open state.

openboolean

The controlled open state of the dialog. Can be bind as v-model:open.

pohon{ root?: ClassValue; wrapper?: ClassValue; title?: ClassValue; description?: ClassValue; icon?: ClassValue; avatar?: ClassValue; avatarSize?: ClassValue; actions?: ClassValue; progress?: ClassValue; close?: ClassValue; }

Slots

Slot Type
leading{ pohon: object; }
titleobject
descriptionobject
actionsobject
close{ pohon: object; }

Emits

Event Type
escapeKeyDown[event: KeyboardEvent]
pause[]
resume[]
swipeStart[event: SwipeEvent]
swipeMove[event: SwipeEvent]
swipeCancel[event: SwipeEvent]
swipeEnd[event: SwipeEvent]
update:open[value: boolean]

Expose

When accessing the component via a template ref, you can use the following:

NameType
heightRef<number>

Theme

We use unocss-variants to customize the theme. Read more about it in the theming guide.

Below is the theme configuration skeleton for the PToast. Since the component is provided unstyled by default, you will need to fill in these values to apply your own custom look and feel. If you prefer to use our pre-built, opinionated styling, you can instead use our UnoCSS preset, this docs is using it as well.

app.config.ts
export default defineAppConfig({
  pohon: {
    toast: {
      slots: {
        root: '',
        wrapper: '',
        title: '',
        description: '',
        icon: '',
        avatar: '',
        avatarSize: '',
        actions: '',
        progress: '',
        close: ''
      },
      variants: {
        color: {
          primary: {
            root: '',
            icon: ''
          },
          secondary: {
            root: '',
            icon: ''
          },
          success: {
            root: '',
            icon: ''
          },
          info: {
            root: '',
            icon: ''
          },
          warning: {
            root: '',
            icon: ''
          },
          error: {
            root: '',
            icon: ''
          },
          neutral: {
            root: '',
            icon: ''
          }
        },
        orientation: {
          horizontal: {
            root: '',
            actions: ''
          },
          vertical: {
            root: '',
            actions: ''
          }
        },
        title: {
          true: {
            description: ''
          }
        }
      },
      compoundVariants: [],
      defaultVariants: {
        color: 'primary'
      }
    }
  }
};
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import pohon from 'pohon-ui/vite'

export default defineAppConfig({
  pohon: {
    toast: {
      slots: {
        root: '',
        wrapper: '',
        title: '',
        description: '',
        icon: '',
        avatar: '',
        avatarSize: '',
        actions: '',
        progress: '',
        close: ''
      },
      variants: {
        color: {
          primary: {
            root: '',
            icon: ''
          },
          secondary: {
            root: '',
            icon: ''
          },
          success: {
            root: '',
            icon: ''
          },
          info: {
            root: '',
            icon: ''
          },
          warning: {
            root: '',
            icon: ''
          },
          error: {
            root: '',
            icon: ''
          },
          neutral: {
            root: '',
            icon: ''
          }
        },
        orientation: {
          horizontal: {
            root: '',
            actions: ''
          },
          vertical: {
            root: '',
            actions: ''
          }
        },
        title: {
          true: {
            description: ''
          }
        }
      },
      compoundVariants: [],
      defaultVariants: {
        color: 'primary'
      }
    }
  }
};

Akar

With Pohon UI, you can achieve similar component functionality with less code and effort, as it comes with built-in styles mechanism and behaviors that are optimized for common use cases. Since it's using unocss-variants it adds a runtime cost, but it can be worth it if you prioritize development speed and ease of use over fine-grained control.

If this is a deal breaker for you, you can always stick to using Akar and build your own custom components on top of it.

Changelog

No recent changes