Skip to content

Toast

Experimental Alpha

This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.

Toast notification is a non-modal element that appears at viewport edges or corners to provide brief, contextual feedback to a user. It can auto-dismiss after a duration and support pause-on-hover behavior.

Examples

Vue
Lit
React
Live Preview

Demo Pattern: Single Toast Display

This demo automatically dismisses any visible toast before showing a new one. This prevents toast overlap and is the recommended pattern for most applications. See the documentation below for alternative approaches if you need multiple simultaneous toasts.

Toast Types

Default toast notification Operation completed successfully! New message received! New feature available!
Warning: This action cannot be undone.
An error occurred. Please try again.
Critical error detected!
Modern monochrome notification

Positions

Toast at top-start Toast at top (full width) Toast at top-end (default) Toast at bottom-start Toast at bottom (full width) Toast at bottom-end

Border Styles

Toast with border
Toast with left border accent
Toast without rounded corners

Auto-Dismiss Options

This toast will auto-dismiss in 2 seconds This toast will auto-dismiss in 5 seconds (default) This toast will not auto-dismiss. Click X to close. Hover won't pause this toast's timer

Close Button Options

Toast without close button (auto-dismisses)

With Icons

File uploaded successfully!
You have 3 unread messages

CSS Shadow Parts Customization

Customize toast appearance using CSS Shadow Parts without breaking encapsulation.

Custom styled toast with gradient

Implementation Patterns

Single Toast (Recommended)

Show one toast at a time to prevent information overload. This demo uses a registry pattern to automatically dismiss the active toast before showing a new one.

// Create registry and track active toast
const toastRefs = { showSuccess, showError /* ... */ };
let activeToastKey = null;

const showToast = (toastKey) => {
  if (activeToastKey) toastRefs[activeToastKey].value = false;
  toastRefs[toastKey].value = true;
  activeToastKey = toastKey;
};

Multiple Toasts (Advanced)

For simultaneous toasts, implement a queue with unique IDs and render to document.body using your framework's approach:

  • Vue: <teleport to="body">
  • React: ReactDOM.createPortal()
  • Svelte: Custom action or onMount
  • Lit/Web Components: Append container to document.body

Key: Maintain toast queue, calculate offsets for stacking, handle enter/exit animations.

Best Practices

  • Limit frequency and keep messages brief
  • Use appropriate types (error for critical, info for general)
  • Important messages need longer durations or manual dismissal
  • Test positioning on mobile to avoid obscuring content
View Vue Code
<template>
  <section>
    <!-- Guidance Note -->
    <div class="mbe4 guidance-note">
      <h3>Demo Pattern: Single Toast Display</h3>
      <p>
        This demo automatically dismisses any visible toast before showing a new one. This prevents toast overlap and is the recommended pattern for most applications.
        See the documentation below for alternative approaches if you need multiple simultaneous toasts.
      </p>
    </div>
    <div class="mbe4">
      <h2>Toast Types</h2>
    </div>
    <div class="stacked flex-align-start mbe4">
      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showDefault')"
      >
        Show Default Toast
      </VueButton>
      <VueToast
        v-model:open="showDefault"
        @toast-close="showDefault = false"
      >
        Default toast notification
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showSuccess')"
      >
        Show Success Toast
      </VueButton>
      <VueToast
        v-model:open="showSuccess"
        type="success"
        @toast-close="showSuccess = false"
      >
        Operation completed successfully!
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showInfo')"
      >
        Show Info Toast
      </VueButton>
      <VueToast
        v-model:open="showInfo"
        type="info"
        @toast-close="showInfo = false"
      >
        New message received!
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showPrimary')"
      >
        Show Primary Toast
      </VueButton>
      <VueToast
        v-model:open="showPrimary"
        type="primary"
        @toast-close="showPrimary = false"
      >
        New feature available!
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showWarning')"
      >
        Show Warning Toast
      </VueButton>
      <VueToast
        v-model:open="showWarning"
        type="warning"
        @toast-close="showWarning = false"
      >
        <div class="flex-inline items-center">
          <AlertTriangle
            :size="20"
            class="mie3"
          />
          Warning: This action cannot be undone.
        </div>
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showError')"
      >
        Show Error Toast
      </VueButton>
      <VueToast
        v-model:open="showError"
        type="error"
        @toast-close="showError = false"
      >
        <div class="flex-inline items-center">
          <AlertCircle
            :size="20"
            class="mie3"
          />
          An error occurred. Please try again.
        </div>
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showDanger')"
      >
        Show Danger Toast
      </VueButton>
      <VueToast
        v-model:open="showDanger"
        type="danger"
        @toast-close="showDanger = false"
      >
        <div class="flex-inline items-center">
          <XCircle
            :size="20"
            class="mie3"
          />
          Critical error detected!
        </div>
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showMonochrome')"
      >
        Show Monochrome Toast
      </VueButton>
      <VueToast
        v-model:open="showMonochrome"
        type="monochrome"
        @toast-close="showMonochrome = false"
      >
        <div class="flex-inline items-center">
          Modern monochrome notification
        </div>
      </VueToast>
    </div>

    <div class="mbe4">
      <h2>Positions</h2>
    </div>
    <div class="stacked flex-align-start mbe4">
      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showTopStart')"
      >
        Top Start
      </VueButton>
      <VueToast
        v-model:open="showTopStart"
        position="top-start"
        @toast-close="showTopStart = false"
      >
        Toast at top-start
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showTop')"
      >
        Top (Full Width)
      </VueButton>
      <VueToast
        v-model:open="showTop"
        position="top"
        @toast-close="showTop = false"
      >
        Toast at top (full width)
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showTopEnd')"
      >
        Top End (Default)
      </VueButton>
      <VueToast
        v-model:open="showTopEnd"
        position="top-end"
        @toast-close="showTopEnd = false"
      >
        Toast at top-end (default)
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showBottomStart')"
      >
        Bottom Start
      </VueButton>
      <VueToast
        v-model:open="showBottomStart"
        position="bottom-start"
        @toast-close="showBottomStart = false"
      >
        Toast at bottom-start
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showBottom')"
      >
        Bottom (Full Width)
      </VueButton>
      <VueToast
        v-model:open="showBottom"
        position="bottom"
        @toast-close="showBottom = false"
      >
        Toast at bottom (full width)
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showBottomEnd')"
      >
        Bottom End
      </VueButton>
      <VueToast
        v-model:open="showBottomEnd"
        position="bottom-end"
        @toast-close="showBottomEnd = false"
      >
        Toast at bottom-end
      </VueToast>
    </div>

    <div class="mbe4">
      <h2>Border Styles</h2>
    </div>
    <div class="stacked flex-align-start mbe4">
      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showBordered')"
      >
        Bordered Toast
      </VueButton>
      <VueToast
        v-model:open="showBordered"
        type="info"
        bordered
        @toast-close="showBordered = false"
      >
        Toast with border
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showBorderedLeft')"
      >
        Left Border Toast
      </VueButton>
      <VueToast
        v-model:open="showBorderedLeft"
        type="success"
        borderedLeft
        @toast-close="showBorderedLeft = false"
      >
        <div class="flex-inline items-center">
          <CheckCircle
            :size="20"
            class="mie3"
          />
          Toast with left border accent
        </div>
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showNotRounded')"
      >
        Not Rounded Toast
      </VueButton>
      <VueToast
        v-model:open="showNotRounded"
        type="primary"
        :rounded="false"
        @toast-close="showNotRounded = false"
      >
        Toast without rounded corners
      </VueToast>
    </div>

    <div class="mbe4">
      <h2>Auto-Dismiss Options</h2>
    </div>
    <div class="stacked flex-align-start mbe4">
      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showQuickDismiss')"
      >
        Quick Dismiss (2s)
      </VueButton>
      <VueToast
        v-model:open="showQuickDismiss"
        :duration="2000"
        type="info"
        @toast-close="showQuickDismiss = false"
      >
        This toast will auto-dismiss in 2 seconds
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showAutoDismiss')"
      >
        Auto-Dismiss (5s)
      </VueButton>
      <VueToast
        v-model:open="showAutoDismiss"
        :duration="5000"
        type="info"
        @toast-close="showAutoDismiss = false"
      >
        This toast will auto-dismiss in 5 seconds (default)
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showNoAutoDismiss')"
      >
        No Auto-Dismiss
      </VueButton>
      <VueToast
        v-model:open="showNoAutoDismiss"
        :auto-dismiss="false"
        type="warning"
        @toast-close="showNoAutoDismiss = false"
      >
        This toast will not auto-dismiss. Click X to close.
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showNoPause')"
      >
        No Pause on Hover
      </VueButton>
      <VueToast
        v-model:open="showNoPause"
        :pause-on-hover="false"
        :duration="3000"
        type="info"
        @toast-close="showNoPause = false"
      >
        Hover won't pause this toast's timer
      </VueToast>
    </div>

    <div class="mbe4">
      <h2>Close Button Options</h2>
    </div>
    <div class="stacked flex-align-start mbe4">
      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showNoCloseButton')"
      >
        No Close Button
      </VueButton>
      <VueToast
        v-model:open="showNoCloseButton"
        :show-close-button="false"
        type="info"
        :duration="3000"
        @toast-close="showNoCloseButton = false"
      >
        Toast without close button (auto-dismisses)
      </VueToast>
    </div>

    <div class="mbe4">
      <h2>With Icons</h2>
    </div>
    <div class="stacked flex-align-start mbe4">
      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showIconSuccess')"
      >
        Success with Icon
      </VueButton>
      <VueToast
        v-model:open="showIconSuccess"
        type="success"
        @toast-close="showIconSuccess = false"
      >
        <div class="flex-inline items-center">
          <CheckCircle
            :size="20"
            class="mie3"
          />
          File uploaded successfully!
        </div>
      </VueToast>

      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showIconInfo')"
      >
        Info with Icon
      </VueButton>
      <VueToast
        v-model:open="showIconInfo"
        type="info"
        @toast-close="showIconInfo = false"
      >
        <div class="flex-inline items-center">
          <Info
            :size="20"
            class="mie3"
          />
          You have 3 unread messages
        </div>
      </VueToast>
    </div>

    <div class="mbe4">
      <h2>CSS Shadow Parts Customization</h2>
      <p
        class="mbe2"
        style="color: var(--ag-text-secondary); font-size: 0.875rem;"
      >
        Customize toast appearance using CSS Shadow Parts without breaking encapsulation.
      </p>
    </div>
    <div class="stacked flex-align-start mbe4">
      <VueButton
        class="demo-button"
        variant="primary"
        size="md"
        shape="rounded"
        @click="showToast('showCustomGradient')"
      >
        Custom Gradient Toast
      </VueButton>
      <VueToast
        v-model:open="showCustomGradient"
        class="custom-gradient-toast"
        position="top-end"
        @toast-close="showCustomGradient = false"
      >
        <div class="flex-inline items-center">
          <Sparkles
            :size="20"
            class="mie3"
          />
          Custom styled toast with gradient
        </div>
      </VueToast>
    </div>
    <!-- Implementation Guide -->
    <div class="mbe4 implementation-guide">
      <h2>Implementation Patterns</h2>

      <div class="guide-section">
        <h3>Single Toast (Recommended)</h3>
        <p>
          Show one toast at a time to prevent information overload. This demo uses a registry pattern to automatically dismiss the active toast before showing a new one.
        </p>
        <pre><code>// Create registry and track active toast
const toastRefs = { showSuccess, showError /* ... */ };
let activeToastKey = null;

const showToast = (toastKey) => {
  if (activeToastKey) toastRefs[activeToastKey].value = false;
  toastRefs[toastKey].value = true;
  activeToastKey = toastKey;
};</code></pre>
      </div>

      <div class="guide-section">
        <h3>Multiple Toasts (Advanced)</h3>
        <p>
          For simultaneous toasts, implement a queue with unique IDs and render to document.body using your framework's approach:
        </p>
        <ul>
          <li><strong>Vue:</strong> <code>&lt;teleport to="body"&gt;</code></li>
          <li><strong>React:</strong> <code>ReactDOM.createPortal()</code></li>
          <li><strong>Svelte:</strong> Custom action or <code>onMount</code></li>
          <li><strong>Lit/Web Components:</strong> Append container to <code>document.body</code></li>
        </ul>
        <p style="color: var(--ag-text-secondary); font-size: 0.875rem; margin-top: 0.5rem;">
          Key: Maintain toast queue, calculate offsets for stacking, handle enter/exit animations.
        </p>
      </div>

      <div class="guide-section">
        <h3>Best Practices</h3>
        <ul>
          <li>Limit frequency and keep messages brief</li>
          <li>Use appropriate types (error for critical, info for general)</li>
          <li>Important messages need longer durations or manual dismissal</li>
          <li>Test positioning on mobile to avoid obscuring content</li>
        </ul>
      </div>
    </div>
  </section>
</template>

<script lang="ts">
import { defineComponent, ref, type Ref } from "vue";
import { VueToast } from "agnosticui-core/toast/vue";
import { VueButton } from "agnosticui-core/button/vue";
import {
  AlertTriangle,
  AlertCircle,
  XCircle,
  CheckCircle,
  Info,
  Sparkles,
} from "lucide-vue-next";

export default defineComponent({
  name: "ToastExamples",
  components: {
    VueToast,
    AlertTriangle,
    AlertCircle,
    XCircle,
    CheckCircle,
    Info,
    Sparkles,
  },
  setup() {
    const showDefault = ref(false);
    const showSuccess = ref(false);
    const showInfo = ref(false);
    const showPrimary = ref(false);
    const showWarning = ref(false);
    const showError = ref(false);
    const showDanger = ref(false);
    const showMonochrome = ref(false);

    const showTopStart = ref(false);
    const showTop = ref(false);
    const showTopEnd = ref(false);
    const showBottomStart = ref(false);
    const showBottom = ref(false);
    const showBottomEnd = ref(false);

    const showBordered = ref(false);
    const showBorderedLeft = ref(false);
    const showNotRounded = ref(false);

    const showQuickDismiss = ref(false);
    const showAutoDismiss = ref(false);
    const showNoAutoDismiss = ref(false);
    const showNoPause = ref(false);

    const showNoCloseButton = ref(false);
    const showIconSuccess = ref(false);
    const showIconInfo = ref(false);
    const showCustomGradient = ref(false);

    //
    // === TOAST REGISTRY FOR SINGLE ACTIVE TOAST TRACKING ===
    //
    const toastRefs: Record<string, Ref<boolean>> = {
      showDefault,
      showSuccess,
      showInfo,
      showPrimary,
      showWarning,
      showError,
      showDanger,
      showMonochrome,
      showTopStart,
      showTop,
      showTopEnd,
      showBottomStart,
      showBottom,
      showBottomEnd,
      showBordered,
      showBorderedLeft,
      showNotRounded,
      showQuickDismiss,
      showAutoDismiss,
      showNoAutoDismiss,
      showNoPause,
      showNoCloseButton,
      showIconSuccess,
      showIconInfo,
      showCustomGradient,
    };

    let activeToastKey: string | null = null;

    function showToast(toastKey: string) {
      // If another toast is active and it's not the same one, close it
      if (activeToastKey && activeToastKey !== toastKey) {
        toastRefs[activeToastKey].value = false;
      }

      // Show the new toast
      toastRefs[toastKey].value = true;
      activeToastKey = toastKey;
    }

    //
    // === RETURN EVERYTHING TO TEMPLATE ===
    //
    return {
      showDefault,
      showSuccess,
      showInfo,
      showPrimary,
      showWarning,
      showError,
      showDanger,
      showMonochrome,
      showTopStart,
      showTop,
      showTopEnd,
      showBottomStart,
      showBottom,
      showBottomEnd,
      showBordered,
      showBorderedLeft,
      showNotRounded,
      showQuickDismiss,
      showAutoDismiss,
      showNoAutoDismiss,
      showNoPause,
      showNoCloseButton,
      showIconSuccess,
      showIconInfo,
      showCustomGradient,
      showToast,
    };
  },
});
</script>

<style scoped>
/* Demo button styling */
.demo-button {
  padding: 0.5rem 1rem;
  background: var(--ag-primary);
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 500;
  transition: background 0.2s ease;
  width: fit-content;
}

.demo-button:hover {
  background: var(--ag-primary-dark);
}

.demo-button:active {
  transform: scale(0.98);
}

/* CSS Shadow Parts customization examples */
.custom-gradient-toast::part(ag-toast) {
  box-shadow: 0 10px 40px rgba(102, 126, 234, 0.4);
}

.custom-gradient-toast::part(ag-toast-content) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  font-weight: 600;
  border: none;
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from 'lit';
import 'agnosticui-core/toast';
import 'agnosticui-core/button';
import 'agnosticui-core/icon';

const toastKeys = [
  "showDefault", "showSuccess", "showInfo", "showPrimary", "showWarning",
  "showError", "showDanger", "showMonochrome", "showTopStart", "showTop",
  "showTopEnd", "showBottomStart", "showBottom", "showBottomEnd", "showBordered",
  "showBorderedLeft", "showNotRounded", "showQuickDismiss", "showAutoDismiss",
  "showNoAutoDismiss", "showNoPause", "showNoCloseButton", "showIconSuccess",
  "showIconInfo", "showCustomGradient",
];

const initialToastsState = toastKeys.reduce((acc, key) => ({ ...acc, [key]: false }), {});

export class ToastLitExamples extends LitElement {
  static get properties() {
    return {
      toasts: { type: Object, state: true },
    };
  }

  constructor() {
    super();
    this.toasts = initialToastsState;
    this.activeToastKey = null;
  }
  
  // No shadow DOM
  createRenderRoot() {
    return this;
  }

  showToast(toastKey) {
    let newToasts = { ...this.toasts };
    if (this.activeToastKey && this.activeToastKey !== toastKey) {
      newToasts[this.activeToastKey] = false;
    }
    newToasts[toastKey] = true;
    this.toasts = newToasts;
    this.activeToastKey = toastKey;
  }

  closeToast(toastKey) {
    this.toasts = { ...this.toasts, [toastKey]: false };
    if (this.activeToastKey === toastKey) {
      this.activeToastKey = null;
    }
  }

  render() {
    return html`
      <section>
        <div class="mbe4 guidance-note">
          <h3>Demo Pattern: Single Toast Display</h3>
          <p>
            This demo automatically dismisses any visible toast before showing a new one. This prevents toast overlap and is the recommended pattern for most applications.
            See the documentation below for alternative approaches if you need multiple simultaneous toasts.
          </p>
        </div>
        <div class="mbe4">
          <h2>Toast Types</h2>
        </div>
        <div class="stacked flex-align-start mbe4">
          <ag-button class="demo-button" @click=${() => this.showToast('showDefault')}>Show Default Toast</ag-button>
          <ag-toast .open=${this.toasts.showDefault} @toast-close=${() => this.closeToast('showDefault')}>Default toast notification</ag-toast>
          
          <ag-button class="demo-button" @click=${() => this.showToast('showSuccess')}>Show Success Toast</ag-button>
          <ag-toast .open=${this.toasts.showSuccess} type="success" @toast-close=${() => this.closeToast('showSuccess')}>Operation completed successfully!</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showInfo')}>Show Info Toast</ag-button>
          <ag-toast .open=${this.toasts.showInfo} type="info" @toast-close=${() => this.closeToast('showInfo')}>New message received!</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showPrimary')}>Show Primary Toast</ag-button>
          <ag-toast .open=${this.toasts.showPrimary} type="primary" @toast-close=${() => this.closeToast('showPrimary')}>New feature available!</ag-toast>
          
          <ag-button class="demo-button" @click=${() => this.showToast('showWarning')}>Show Warning Toast</ag-button>
          <ag-toast .open=${this.toasts.showWarning} type="warning" @toast-close=${() => this.closeToast('showWarning')}>
            <div class="flex-inline items-center"><ag-icon size="20" class="mie3"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path><line x1="12" x2="12" y1="9" y2="13"></line><line x1="12" x2="12.01" y1="17" y2="17"></line></svg></ag-icon>Warning: This action cannot be undone.</div>
          </ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showError')}>Show Error Toast</ag-button>
          <ag-toast .open=${this.toasts.showError} type="error" @toast-close=${() => this.closeToast('showError')}>
            <div class="flex-inline items-center"><ag-icon size="20" class="mie3"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" x2="12" y1="8" y2="12"></line><line x1="12" x2="12.01" y1="16" y2="16"></line></svg></ag-icon>An error occurred. Please try again.</div>
          </ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showDanger')}>Show Danger Toast</ag-button>
          <ag-toast .open=${this.toasts.showDanger} type="danger" @toast-close=${() => this.closeToast('showDanger')}>
            <div class="flex-inline items-center"><ag-icon size="20" class="mie3"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="15" x2="9" y1="9" y2="15"></line><line x1="9" x2="15" y1="9" y2="15"></line></svg></ag-icon>Critical error detected!</div>
          </ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showMonochrome')}>Show Monochrome Toast</ag-button>
          <ag-toast .open=${this.toasts.showMonochrome} type="monochrome" @toast-close=${() => this.closeToast('showMonochrome')}>
            <div class="flex-inline items-center">Modern monochrome notification</div>
          </ag-toast>
        </div>

        <div class="mbe4">
          <h2>Positions</h2>
        </div>
        <div class="stacked flex-align-start mbe4">
          <ag-button class="demo-button" @click=${() => this.showToast('showTopStart')}>Top Start</ag-button>
          <ag-toast .open=${this.toasts.showTopStart} position="top-start" @toast-close=${() => this.closeToast('showTopStart')}>Toast at top-start</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showTop')}>Top (Full Width)</ag-button>
          <ag-toast .open=${this.toasts.showTop} position="top" @toast-close=${() => this.closeToast('showTop')}>Toast at top (full width)</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showTopEnd')}>Top End (Default)</ag-button>
          <ag-toast .open=${this.toasts.showTopEnd} position="top-end" @toast-close=${() => this.closeToast('showTopEnd')}>Toast at top-end (default)</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showBottomStart')}>Bottom Start</ag-button>
          <ag-toast .open=${this.toasts.showBottomStart} position="bottom-start" @toast-close=${() => this.closeToast('showBottomStart')}>Toast at bottom-start</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showBottom')}>Bottom (Full Width)</ag-button>
          <ag-toast .open=${this.toasts.showBottom} position="bottom" @toast-close=${() => this.closeToast('showBottom')}>Toast at bottom (full width)</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showBottomEnd')}>Bottom End</ag-button>
          <ag-toast .open=${this.toasts.showBottomEnd} position="bottom-end" @toast-close=${() => this.closeToast('showBottomEnd')}>Toast at bottom-end</ag-toast>
        </div>

        <div class="mbe4">
          <h2>Border Styles</h2>
        </div>
        <div class="stacked flex-align-start mbe4">
          <ag-button class="demo-button" @click=${() => this.showToast('showBordered')}>Bordered Toast</ag-button>
          <ag-toast .open=${this.toasts.showBordered} type="info" bordered @toast-close=${() => this.closeToast('showBordered')}>Toast with border</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showBorderedLeft')}>Left Border Toast</ag-button>
          <ag-toast .open=${this.toasts.showBorderedLeft} type="success" borderedLeft @toast-close=${() => this.closeToast('showBorderedLeft')}>
            <div class="flex-inline items-center"><ag-icon size="20" class="mie3"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg></ag-icon>Toast with left border accent</div>
          </ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showNotRounded')}>Not Rounded Toast</ag-button>
          <ag-toast .open=${this.toasts.showNotRounded} type="primary" .rounded=${false} @toast-close=${() => this.closeToast('showNotRounded')}>Toast without rounded corners</ag-toast>
        </div>

        <div class="mbe4">
          <h2>Auto-Dismiss Options</h2>
        </div>
        <div class="stacked flex-align-start mbe4">
          <ag-button class="demo-button" @click=${() => this.showToast('showQuickDismiss')}>Quick Dismiss (2s)</ag-button>
          <ag-toast .open=${this.toasts.showQuickDismiss} .duration=${2000} type="info" @toast-close=${() => this.closeToast('showQuickDismiss')}>This toast will auto-dismiss in 2 seconds</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showAutoDismiss')}>Auto-Dismiss (5s)</ag-button>
          <ag-toast .open=${this.toasts.showAutoDismiss} .duration=${5000} type="info" @toast-close=${() => this.closeToast('showAutoDismiss')}>This toast will auto-dismiss in 5 seconds (default)</ag-toast>
          
          <ag-button class="demo-button" @click=${() => this.showToast('showNoAutoDismiss')}>No Auto-Dismiss</ag-button>
          <ag-toast .open=${this.toasts.showNoAutoDismiss} .autoDismiss=${false} type="warning" @toast-close=${() => this.closeToast('showNoAutoDismiss')}>This toast will not auto-dismiss. Click X to close.</ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showNoPause')}>No Pause on Hover</ag-button>
          <ag-toast .open=${this.toasts.showNoPause} .pauseOnHover=${false} .duration=${3000} type="info" @toast-close=${() => this.closeToast('showNoPause')}>Hover won't pause this toast's timer</ag-toast>
        </div>

        <div class="mbe4">
          <h2>Close Button Options</h2>
        </div>
        <div class="stacked flex-align-start mbe4">
          <ag-button class="demo-button" @click=${() => this.showToast('showNoCloseButton')}>No Close Button</ag-button>
          <ag-toast .open=${this.toasts.showNoCloseButton} .showCloseButton=${false} type="info" .duration=${3000} @toast-close=${() => this.closeToast('showNoCloseButton')}>Toast without close button (auto-dismisses)</ag-toast>
        </div>

        <div class="mbe4">
          <h2>With Icons</h2>
        </div>
        <div class="stacked flex-align-start mbe4">
          <ag-button class="demo-button" @click=${() => this.showToast('showIconSuccess')}>Success with Icon</ag-button>
          <ag-toast .open=${this.toasts.showIconSuccess} type="success" @toast-close=${() => this.closeToast('showIconSuccess')}>
            <div class="flex-inline items-center"><ag-icon size="20" class="mie3"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg></ag-icon>File uploaded successfully!</div>
          </ag-toast>

          <ag-button class="demo-button" @click=${() => this.showToast('showIconInfo')}>Info with Icon</ag-button>
          <ag-toast .open=${this.toasts.showIconInfo} type="info" @toast-close=${() => this.closeToast('showIconInfo')}>
            <div class="flex-inline items-center"><ag-icon size="20" class="mie3"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" x2="12" y1="16" y2="12"></line><line x1="12" x2="12.01" y1="8" y2="8"></line></svg></ag-icon>You have 3 unread messages</div>
          </ag-toast>
        </div>

        <div class="mbe4">
          <h2>CSS Shadow Parts Customization</h2>
          <p class="mbe2" style="color: var(--ag-text-secondary); font-size: 0.875rem;">
            Customize toast appearance using CSS Shadow Parts without breaking encapsulation.
          </p>
        </div>
        <div class="stacked flex-align-start mbe4">
          <ag-button class="demo-button" @click=${() => this.showToast('showCustomGradient')}>Custom Gradient Toast</ag-button>
          <ag-toast
            .open=${this.toasts.showCustomGradient}
            class="custom-gradient-toast"
            position="top-end"
            @toast-close=${() => this.closeToast('showCustomGradient')}
          >
            <div class="flex-inline items-center">
              <ag-icon size="20" class="mie3"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15.6 3.3-3.2 8.7-8.7 3.2 3.2 8.7 8.7-3.2-3.2-8.7-8.7-3.2z"></path></svg></ag-icon>
              Custom styled toast with gradient
            </div>
          </ag-toast>
        </div>
      </section>
    `;
  }
}
customElements.define('toast-lit-examples', ToastLitExamples);

Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.

View React Code
import { useState } from "react";
import { ReactToast } from "agnosticui-core/toast/react";
import { ReactButton } from "agnosticui-core/button/react";
import {
  AlertTriangle,
  AlertCircle,
  XCircle,
  CheckCircle,
  Info,
  Sparkles,
} from "lucide-react";

const toastKeys = [
  "showDefault", "showSuccess", "showInfo", "showPrimary", "showWarning",
  "showError", "showDanger", "showMonochrome", "showTopStart", "showTop",
  "showTopEnd", "showBottomStart", "showBottom", "showBottomEnd", "showBordered",
  "showBorderedLeft", "showNotRounded", "showQuickDismiss", "showAutoDismiss",
  "showNoAutoDismiss", "showNoPause", "showNoCloseButton", "showIconSuccess",
  "showIconInfo", "showCustomGradient",
];

const initialToastsState = toastKeys.reduce((acc, key) => ({ ...acc, [key]: false }), {});

export default function ToastReactExamples() {
  const [toasts, setToasts] = useState(initialToastsState);
  let activeToastKey = null;

  const showToast = (toastKey) => {
    if (activeToastKey && activeToastKey !== toastKey) {
      setToasts(prev => ({ ...prev, [activeToastKey]: false }));
    }
    setToasts(prev => ({ ...prev, [toastKey]: true }));
    activeToastKey = toastKey;
  };

  const closeToast = (toastKey) => {
    setToasts(prev => ({ ...prev, [toastKey]: false }));
    if (activeToastKey === toastKey) {
      activeToastKey = null;
    }
  };

  return (
    <section>
    <div class="mbe4 guidance-note">
      <h3>Demo Pattern: Single Toast Display</h3>
      <p>
        This demo automatically dismisses any visible toast before showing a new one. This prevents toast overlap and is the recommended pattern for most applications.
        See the documentation below for alternative approaches if you need multiple simultaneous toasts.
      </p>
    </div>
    <div className="mbe4">
      <h2>Toast Types</h2>
    </div>
    <div className="stacked flex-align-start mbe4">
        <ReactButton className="demo-button" onClick={() => showToast('showDefault')}>Show Default Toast</ReactButton>
        <ReactToast open={toasts.showDefault} onToastClose={() => closeToast('showDefault')}>Default toast notification</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showSuccess')}>Show Success Toast</ReactButton>
        <ReactToast open={toasts.showSuccess} type="success" onToastClose={() => closeToast('showSuccess')}>Operation completed successfully!</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showInfo')}>Show Info Toast</ReactButton>
        <ReactToast open={toasts.showInfo} type="info" onToastClose={() => closeToast('showInfo')}>New message received!</ReactToast>
        
        <ReactButton className="demo-button" onClick={() => showToast('showPrimary')}>Show Primary Toast</ReactButton>
        <ReactToast open={toasts.showPrimary} type="primary" onToastClose={() => closeToast('showPrimary')}>New feature available!</ReactToast>
        
        <ReactButton className="demo-button" onClick={() => showToast('showWarning')}>Show Warning Toast</ReactButton>
        <ReactToast open={toasts.showWarning} type="warning" onToastClose={() => closeToast('showWarning')}>
          <div className="flex-inline items-center"><AlertTriangle size={20} className="mie3" />Warning: This action cannot be undone.</div>
        </ReactToast>
        
        <ReactButton className="demo-button" onClick={() => showToast('showError')}>Show Error Toast</ReactButton>
        <ReactToast open={toasts.showError} type="error" onToastClose={() => closeToast('showError')}>
          <div className="flex-inline items-center"><AlertCircle size={20} className="mie3" />An error occurred. Please try again.</div>
        </ReactToast>
        
        <ReactButton className="demo-button" onClick={() => showToast('showDanger')}>Show Danger Toast</ReactButton>
        <ReactToast open={toasts.showDanger} type="danger" onToastClose={() => closeToast('showDanger')}>
          <div className="flex-inline items-center"><XCircle size={20} className="mie3" />Critical error detected!</div>
        </ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showMonochrome')}>Show Monochrome Toast</ReactButton>
        <ReactToast open={toasts.showMonochrome} type="monochrome" onToastClose={() => closeToast('showMonochrome')}>
          <div className="flex-inline items-center">Modern monochrome notification</div>
        </ReactToast>
    </div>

    <div className="mbe4">
        <h2>Positions</h2>
    </div>
    <div className="stacked flex-align-start mbe4">
        <ReactButton className="demo-button" onClick={() => showToast('showTopStart')}>Top Start</ReactButton>
        <ReactToast open={toasts.showTopStart} position="top-start" onToastClose={() => closeToast('showTopStart')}>Toast at top-start</ReactToast>
        
        <ReactButton className="demo-button" onClick={() => showToast('showTop')}>Top (Full Width)</ReactButton>
        <ReactToast open={toasts.showTop} position="top" onToastClose={() => closeToast('showTop')}>Toast at top (full width)</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showTopEnd')}>Top End (Default)</ReactButton>
        <ReactToast open={toasts.showTopEnd} position="top-end" onToastClose={() => closeToast('showTopEnd')}>Toast at top-end (default)</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showBottomStart')}>Bottom Start</ReactButton>
        <ReactToast open={toasts.showBottomStart} position="bottom-start" onToastClose={() => closeToast('showBottomStart')}>Toast at bottom-start</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showBottom')}>Bottom (Full Width)</ReactButton>
        <ReactToast open={toasts.showBottom} position="bottom" onToastClose={() => closeToast('showBottom')}>Toast at bottom (full width)</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showBottomEnd')}>Bottom End</ReactButton>
        <ReactToast open={toasts.showBottomEnd} position="bottom-end" onToastClose={() => closeToast('showBottomEnd')}>Toast at bottom-end</ReactToast>
    </div>
    
    <div className="mbe4">
        <h2>Border Styles</h2>
    </div>
    <div className="stacked flex-align-start mbe4">
        <ReactButton className="demo-button" onClick={() => showToast('showBordered')}>Bordered Toast</ReactButton>
        <ReactToast open={toasts.showBordered} type="info" bordered onToastClose={() => closeToast('showBordered')}>Toast with border</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showBorderedLeft')}>Left Border Toast</ReactButton>
        <ReactToast open={toasts.showBorderedLeft} type="success" borderedLeft onToastClose={() => closeToast('showBorderedLeft')}>
            <div className="flex-inline items-center"><CheckCircle size={20} className="mie3" />Toast with left border accent</div>
        </ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showNotRounded')}>Not Rounded Toast</ReactButton>
        <ReactToast open={toasts.showNotRounded} type="primary" rounded={false} onToastClose={() => closeToast('showNotRounded')}>Toast without rounded corners</ReactToast>
    </div>

    <div className="mbe4">
        <h2>Auto-Dismiss Options</h2>
    </div>
    <div className="stacked flex-align-start mbe4">
        <ReactButton className="demo-button" onClick={() => showToast('showQuickDismiss')}>Quick Dismiss (2s)</ReactButton>
        <ReactToast open={toasts.showQuickDismiss} duration={2000} type="info" onToastClose={() => closeToast('showQuickDismiss')}>This toast will auto-dismiss in 2 seconds</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showAutoDismiss')}>Auto-Dismiss (5s)</ReactButton>
        <ReactToast open={toasts.showAutoDismiss} duration={5000} type="info" onToastClose={() => closeToast('showAutoDismiss')}>This toast will auto-dismiss in 5 seconds (default)</ReactToast>
    
        <ReactButton className="demo-button" onClick={() => showToast('showNoAutoDismiss')}>No Auto-Dismiss</ReactButton>
        <ReactToast open={toasts.showNoAutoDismiss} autoDismiss={false} type="warning" onToastClose={() => closeToast('showNoAutoDismiss')}>This toast will not auto-dismiss. Click X to close.</ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showNoPause')}>No Pause on Hover</ReactButton>
        <ReactToast open={toasts.showNoPause} pauseOnHover={false} duration={3000} type="info" onToastClose={() => closeToast('showNoPause')}>Hover won't pause this toast's timer</ReactToast>
    </div>

    <div className="mbe4">
        <h2>Close Button Options</h2>
    </div>
    <div className="stacked flex-align-start mbe4">
        <ReactButton className="demo-button" onClick={() => showToast('showNoCloseButton')}>No Close Button</ReactButton>
        <ReactToast open={toasts.showNoCloseButton} showCloseButton={false} type="info" duration={3000} onToastClose={() => closeToast('showNoCloseButton')}>Toast without close button (auto-dismisses)</ReactToast>
    </div>

    <div className="mbe4">
        <h2>With Icons</h2>
    </div>
    <div className="stacked flex-align-start mbe4">
        <ReactButton className="demo-button" onClick={() => showToast('showIconSuccess')}>Success with Icon</ReactButton>
        <ReactToast open={toasts.showIconSuccess} type="success" onToastClose={() => closeToast('showIconSuccess')}>
            <div className="flex-inline items-center"><CheckCircle size={20} className="mie3" />File uploaded successfully!</div>
        </ReactToast>

        <ReactButton className="demo-button" onClick={() => showToast('showIconInfo')}>Info with Icon</ReactButton>
        <ReactToast open={toasts.showIconInfo} type="info" onToastClose={() => closeToast('showIconInfo')}>
            <div className="flex-inline items-center"><Info size={20} className="mie3" />You have 3 unread messages</div>
        </ReactToast>
    </div>

    <div className="mbe4">
      <h2>CSS Shadow Parts Customization</h2>
      <p
        className="mbe2"
        style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}
      >
        Customize toast appearance using CSS Shadow Parts without breaking encapsulation.
      </p>
    </div>
    <div className="stacked flex-align-start mbe4">
      <ReactButton className="demo-button" onClick={() => showToast('showCustomGradient')}>Custom Gradient Toast</ReactButton>
      <ReactToast
        open={toasts.showCustomGradient}
        className="custom-gradient-toast"
        position="top-end"
        onToastClose={() => closeToast('showCustomGradient')}
      >
        <div className="flex-inline items-center"><Sparkles size={20} className="mie3" />Custom styled toast with gradient</div>
      </ReactToast>
    </div>
    </section>
  );
}
Open in StackBlitz

Props

PropTypeDefaultDescription
openbooleanfalseControls visibility of the toast
type'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'error''default'The toast variant type
position'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'start' | 'end''top-end'Viewport position where the toast appears
durationnumber5000Auto-dismiss duration in milliseconds
autoDismissbooleantrueEnable auto-dismiss functionality
showCloseButtonbooleantrueShow the close button
pauseOnHoverbooleantruePause auto-dismiss timer when hovering
borderedbooleanfalseAdds a border around the toast
roundedbooleantrueApplies rounded corners to the toast
borderedLeftbooleanfalseAdds a left border accent to the toast

Events

EventFrameworkDetailDescription
toast-openVue: @toast-open
React: onToastOpen
Lit: @toast-open
voidEmitted when toast becomes visible
toast-closeVue: @toast-close
React: onToastClose
Lit: @toast-close
voidEmitted when toast is closed (manually or via auto-dismiss)
toast-dismissVue: @toast-dismiss
React: onToastDismiss
Lit: @toast-dismiss
voidEmitted specifically when auto-dismiss timer completes (not when closed manually)

Note: All events use the dual-dispatch pattern:

  • Native web component events (toast-open, toast-close, toast-dismiss) are dispatched with bubbles: true and composed: true
  • Callback props (onToastOpen, onToastClose, onToastDismiss) are also invoked when set

Event Handling Examples

Vue
vue
<template>
  <VueToast
    v-model:open="showToast"
    @toast-open="handleOpen"
    @toast-close="handleClose"
    @toast-dismiss="handleDismiss"
  >
    Toast with event handlers
  </VueToast>
</template>

<script setup>
import { ref } from 'vue';
import { VueToast } from 'agnosticui-core/toast/vue';

const showToast = ref(false);

const handleOpen = () => {
  console.log('Toast opened');
};

const handleClose = () => {
  console.log('Toast closed');
};

const handleDismiss = () => {
  console.log('Toast auto-dismissed');
};
</script>
React
tsx
import { useState } from 'react';
import { ReactToast } from 'agnosticui-core/toast/react';

export default function Example() {
  const [showToast, setShowToast] = useState(false);

  const handleOpen = () => {
    console.log('Toast opened');
  };

  const handleClose = () => {
    console.log('Toast closed');
    setShowToast(false);
  };

  const handleDismiss = () => {
    console.log('Toast auto-dismissed');
  };

  return (
    <ReactToast
      open={showToast}
      onToastOpen={handleOpen}
      onToastClose={handleClose}
      onToastDismiss={handleDismiss}
    >
      Toast with event handlers
    </ReactToast>
  );
}
Lit (Web Components)
html
<script type="module">
  import 'agnosticui-core/toast';

  const toast = document.querySelector('#toast-with-events');
  
  toast.addEventListener('toast-open', () => {
    console.log('Toast opened');
  });
  
  toast.addEventListener('toast-close', () => {
    console.log('Toast closed');
  });
  
  toast.addEventListener('toast-dismiss', () => {
    console.log('Toast auto-dismissed');
  });
</script>

<ag-toast id="toast-with-events">
  Toast with event handlers
</ag-toast>

CSS Shadow Parts

Shadow Parts allow you to style internal elements of the toast from outside the shadow DOM using the ::part() CSS selector.

PartDescription
ag-toastThe outer container element
ag-toast-contentThe content wrapper (wraps the alert component)

Customization Example

css
/* Customize the toast container */
ag-toast::part(ag-toast) {
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(10px);
}

/* Customize the content wrapper */
ag-toast::part(ag-toast-content) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  font-weight: 600;
  border: none;
}

Accessibility

The Toast component is designed to be accessible by default:

  • ARIA Role: Uses role="status" for informational toasts and role="alert" for urgent types (error, danger, warning)
  • ARIA Live Region: Automatically sets aria-live="polite" for normal toasts and aria-live="assertive" for urgent toasts
  • ARIA Atomic: Uses aria-atomic="true" to ensure the entire message is announced
  • Keyboard Support: Press Escape to dismiss toast when close button is visible
  • Focus Management: Toast appears without stealing focus, allowing users to continue their work
  • Pause on Hover: Auto-dismiss pauses when hovering, giving users more time to read

Best Practices

  • Keep Messages Brief: Toast messages should be concise and easily scannable
  • Use Appropriate Types: Use error/danger for critical errors, warning for important cautions, success for confirmations, and info for general notifications
  • Consider Auto-Dismiss: For non-critical messages, enable auto-dismiss. For important messages requiring action, disable auto-dismiss or use longer durations
  • Position Thoughtfully: Place toasts where they won't obscure important content. Top-end is conventional for most applications
  • Limit Frequency: Avoid overwhelming users with too many toast notifications

Common Patterns

Toast with Icon

vue
<template>
  <VueToast v-model:open="showToast" type="success">
    <div style="display: flex; align-items: center; gap: 0.5rem;">
      <CheckCircle :size="20" />
      <span>Profile updated successfully!</span>
    </div>
  </VueToast>
</template>

<script setup>
import { CheckCircle } from 'lucide-vue-next';
import { VueToast } from 'agnosticui-core/toast/vue';
</script>

Notes

  • Type variants: Both type="error" and type="danger" are supported and interchangeable (they render identically)
  • Position behavior: Corner positions (e.g., top-end) have max-width constraints (400px) while edge positions (e.g., top) span the full width
  • Animation: Toasts animate in from their position direction (top positions slide down, bottom positions slide up, etc.)
  • Reduced motion: Respects prefers-reduced-motion and uses only opacity transitions when enabled
  • Stacking: Multiple toasts at the same position will overlap. See the Implementation Guide in the Examples section above for patterns on managing multiple toasts.