Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UI ARC Radiant Components
v4.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Toast

Stack-managed notification toasts with auto-dismiss, variant-colored indicators, configurable position, and smooth enter/exit animations.

Components Toast
feedback interactive
<arc-toast>

Overview

Toast provides a stack-managed notification system that surfaces brief, non-blocking messages to the user. Unlike modals or alerts, toasts appear in a fixed corner of the viewport and dismiss themselves automatically, making them ideal for confirming background operations — file saved, record updated, network reconnected — without interrupting the user's workflow. A single `<arc-toast>` element acts as the toaster: you place it once in your layout and call its `show()` method imperatively whenever a notification needs to appear. Each call pushes a new toast onto the stack. Multiple toasts stack vertically with consistent spacing, and each one exits with a scale-and-fade animation after the configured duration. This imperative API keeps your template clean — there is no need to manage an array of open notifications in your component state. **Queueing is built in.** `max-visible` (default 3) caps how many toasts are on screen at once; the rest wait and appear as slots free up, with `queue-limit` bounding the backlog. Set `max-visible="0"` for unbounded stacking. `dedupe` collapses a repeat of a message already showing into a "(×N)" counter on the existing toast — updated in place, so nothing flickers — and restarts its timer, so a message that keeps repeating stays on screen while it does. `arc-queue-change` reports the visible and queued counts; `arc-queue-overflow` fires when the backlog is full and the oldest queued toast is dropped. `show()` returns the id it assigned, and `dismiss(id)` removes that toast whether it is visible or still queued. Toasts can also be raised from anywhere without a reference to the element: dispatch an `arc-toast` event on `document` with the same options `show()` takes. **Progress mode** covers long-running work. Pass a numeric `progress` to `show()` and the toast renders a track beneath its message, then exempts itself from the two behaviours that assume a message is momentary: it is never deduped, and it never auto-dismisses. Two uploads of a file with the same name are two uploads, so coalescing them would leave one bar tracking both; and the toast ends when the work does, not when a timer says so. Move the bar with `updateToast(id, { progress })` — which can revise the message in the same call — and finish with `complete(id)`, which dismisses it and fires `arc-complete`. Supplying an `onCancel` callback turns the close button into a cancel button and fires `arc-cancel`; without one the toast keeps an ordinary dismiss. `complete` is deliberately not `dismiss`: the operation finishing and the user closing the toast are different events, and code waiting on the first should not be woken by the second. The mode is chosen at `show()` and cannot be switched on later — a track appearing mid-life would relayout a notification the reader is already reading. **An action button** turns a toast into an undo or a retry. `actionLabel` renders a ghost button in the toast, and a click runs the `action` callback, fires `arc-action`, and dismisses. Both the callback and the event exist because a callback cannot be attached declaratively, and either is a valid way to listen. Four built-in variants — info, success, warning, and error — apply a colored bottom-edge indicator and a matching icon so users can parse the severity at a glance. The six position options let you anchor the toast stack to any corner or center-edge of the viewport, and a responsive breakpoint ensures toasts span the full width on small screens. The container carries `role="status"` and `aria-live="polite"` so screen readers announce new messages without stealing focus.

Guidelines

When to use

  • Place a single <arc-toast> element at the root of your layout so all pages share one toaster
  • Use the success variant to confirm completed actions like saves, uploads, and deletions
  • Keep messages short — one sentence or less — so users can read them before auto-dismiss
  • Use the error variant for failures that need acknowledgment but not a blocking dialog
  • Set duration to 0 for critical messages that the user must dismiss manually
  • Pair with form submissions and async operations to provide immediate feedback
  • Use progress mode for work with a knowable percentage — uploads, exports, batch jobs
  • Give a progress toast an onCancel whenever the work can actually be abandoned, so the button means something
  • Call complete(id) when the work finishes, so listeners can tell completion from the user closing the toast

When not to use

  • Do not create multiple <arc-toast> elements on the same page — use one shared instance
  • Do not use toasts for information that requires user decision or input; use a Dialog, or Confirm for a yes/no
  • Do not display sensitive data (passwords, tokens) in a toast — they are visible to anyone nearby
  • Do not set very short durations (under 2 000 ms); users may not have time to read the message
  • Do not rely solely on color to convey meaning — the icon and message text must stand on their own
  • Do not fire toasts in rapid succession for batch operations; summarize into a single notification
  • Do not use progress mode for work of unknown duration — a bar that cannot advance honestly is a Spinner
  • Do not leave a progress toast open after its work ends; it never auto-dismisses, so complete(id) or dismiss(id) is required
  • Do not put the only route to an irreversible action in a toast action button — it dismisses on its own

Features

  • Imperative show() API — call with message, variant, and optional duration; returns the toast id
  • `max-visible` caps on-screen toasts (default 3) and queues the rest; `queue-limit` bounds the backlog
  • `dedupe` collapses a repeated message into a "(×N)" counter, updated in place
  • `dismiss(id)` removes a toast whether it is visible or still queued
  • Progress mode — pass `progress` to `show()` for a track that skips dedupe and never auto-dismisses
  • `updateToast(id, { progress, message })` moves the bar and revises the text; `complete(id)` ends it and fires `arc-complete`
  • `onCancel` turns the close button into a cancel button and fires `arc-cancel`
  • `action` and `actionLabel` render an undo/retry button that fires `arc-action` before dismissing
  • Document-level `arc-toast` event raises a toast without a reference to the element
  • `arc-queue-change` and `arc-queue-overflow` report queue state
  • Four variants (info, success, warning, error) with color-coded bottom indicators and icons
  • Six position anchors: top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
  • Auto-dismiss after configurable duration (default 4 000 ms); pass 0 to persist
  • Smooth enter/exit animations with scale and opacity transitions
  • Manual dismiss via close button on each toast
  • Vertical stacking with consistent gap for multiple simultaneous toasts
  • aria-live="polite" container for screen-reader announcements
  • Respects `prefers-reduced-motion` — disables animations when set
  • Responsive full-width layout on viewports under 640 px
  • `arc-close` event fires when a toast is removed

Preview

Show Success ToastShow Error ToastUpload a File

Usage

This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.

<script type="module" src="@arclux/arc-ui"></script>

<arc-toast id="toaster" position="top-right"></arc-toast>

<div style="display: flex; gap: 8px; flex-wrap: wrap;">
  <arc-button variant="primary"
    onclick="document.getElementById('toaster').show({ message: 'Changes saved successfully.', variant: 'success' })">
    Success
  </arc-button>
  <arc-button variant="secondary"
    onclick="document.getElementById('toaster').show({ message: 'Something went wrong.', variant: 'error' })">
    Error
  </arc-button>
  <arc-button variant="ghost"
    onclick="document.getElementById('toaster').show({ message: 'Deployment in progress...', variant: 'warning', duration: 6000 })">
    Warning (6 s)
  </arc-button>
  <arc-button variant="ghost" onclick="upload()">Upload</arc-button>
</div>

<script>
  // Progress mode: a numeric progress option renders the track. The toast then
  // skips dedupe and never auto-dismisses — it ends when complete() says so.
  async function upload() {
    const toaster = document.getElementById('toaster');
    const controller = new AbortController();
    const id = toaster.show({
      message: 'Uploading report.pdf…',
      progress: 0,
      onCancel: () => controller.abort(),   // this is what renders the cancel button
    });

    try {
      for (let sent = 0; sent <= 100; sent += 10) {
        await sendChunk(sent, { signal: controller.signal });
        toaster.updateToast(id, { progress: sent });
      }
      toaster.updateToast(id, { message: 'Uploaded report.pdf' });
      toaster.complete(id);                 // dismisses and fires arc-complete
    } catch {
      toaster.dismiss(id);
      toaster.show({ message: 'Upload failed.', variant: 'error' });
    }
  }

  // Completion and cancellation are distinct events, so a listener can tell
  // "the work finished" from "the user closed it".
  document.getElementById('toaster').addEventListener('arc-complete', (e) => {
    console.log('upload finished', e.detail.id);
  });
</script>
import { Toast, Button } from '@arclux/arc-ui-react';
import type { ArcToast } from '@arclux/arc-ui/toast';
import { useRef } from 'react';

export function NotificationDemo() {
  // Typing the ref as ArcToast is what makes show()/updateToast()/complete()
  // and the shape of the options object visible to TypeScript.
  const toastRef = useRef<ArcToast>(null);

  const showSuccess = () =>
    toastRef.current?.show({ message: 'Changes saved successfully.', variant: 'success' });
  const showError = () =>
    toastRef.current?.show({ message: 'Something went wrong.', variant: 'error' });

  // Progress mode. show() returns the id every later call needs, and the toast
  // stays until complete() or dismiss() — there is no timer to race.
  const upload = async () => {
    const toaster = toastRef.current;
    if (!toaster) return;
    const controller = new AbortController();
    const id = toaster.show({
      message: 'Uploading report.pdf…',
      progress: 0,
      onCancel: () => controller.abort(),
    });

    for (let sent = 0; sent <= 100; sent += 10) {
      await sendChunk(sent, { signal: controller.signal });
      toaster.updateToast(id, { progress: sent });
    }
    toaster.complete(id);
  };

  return (
    <>
      <Toast ref={toastRef} position="top-right" />
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        <Button variant="primary" onClick={showSuccess}>Success</Button>
        <Button variant="secondary" onClick={showError}>Error</Button>
        <Button variant="ghost" onClick={upload}>Upload</Button>
      </div>
    </>
  );
}
<script setup>
import { ref } from 'vue';
import { Button, Toast } from '@arclux/arc-ui-vue';

const toaster = ref(null);
const showSuccess = () => toaster.value?.show({ message: 'Changes saved successfully.', variant: 'success' });
const showError   = () => toaster.value?.show({ message: 'Something went wrong.', variant: 'error' });
</script>

<template>
  <Toast ref="toaster" position="top-right" />
  <div style="display: flex; gap: 8px; flex-wrap: wrap;">
    <Button variant="primary" @click="showSuccess">Success</Button>
    <Button variant="secondary" @click="showError">Error</Button>
  </div>
</template>
<script>
  import { Button, Toast } from '@arclux/arc-ui-svelte';

  let toaster;
  const showSuccess = () => toaster?.show({ message: 'Changes saved successfully.', variant: 'success' });
  const showError   = () => toaster?.show({ message: 'Something went wrong.', variant: 'error' });
</script>

<Toast bind:this={toaster} position="top-right" />
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
  <Button variant="primary" on:click={showSuccess}>Success</Button>
  <Button variant="secondary" on:click={showError}>Error</Button>
</div>
import { Component, ViewChild, ElementRef } from '@angular/core';
import { Button, Toast } from '@arclux/arc-ui-angular';
import type { ArcToast } from '@arclux/arc-ui/toast';

@Component({
  imports: [Button, Toast],
  template: `
    <arc-toast #toaster position="top-right"></arc-toast>
    <div style="display: flex; gap: 8px; flex-wrap: wrap;">
      <arc-button variant="primary" (click)="showSuccess()">Success</arc-button>
      <arc-button variant="secondary" (click)="showError()">Error</arc-button>
    </div>
  `,
})
export class NotificationDemoComponent {
  @ViewChild('toaster') toaster!: ElementRef<ArcToast>;

  showSuccess() {
    this.toaster.nativeElement.show({ message: 'Changes saved successfully.', variant: 'success' });
  }
  showError() {
    this.toaster.nativeElement.show({ message: 'Something went wrong.', variant: 'error' });
  }
}
import { Button, Toast } from '@arclux/arc-ui-solid';
import type { ArcToast } from '@arclux/arc-ui/toast';

export function NotificationDemo() {
  let toaster: ArcToast | undefined;

  return (
    <>
      <Toast ref={toaster} position="top-right" />
      <div style={{ display: 'flex', gap: '8px', 'flex-wrap': 'wrap' }}>
        <Button variant="primary"
          onClick={() => toaster?.show({ message: 'Changes saved successfully.', variant: 'success' })}>
          Success
        </Button>
        <Button variant="secondary"
          onClick={() => toaster?.show({ message: 'Something went wrong.', variant: 'error' })}>
          Error
        </Button>
      </div>
    </>
  );
}
import { Button, Toast } from '@arclux/arc-ui-preact';
import type { ArcToast } from '@arclux/arc-ui/toast';
import { useRef } from 'preact/hooks';

export function NotificationDemo() {
  const toastRef = useRef<ArcToast>(null);

  const showSuccess = () =>
    toastRef.current?.show({ message: 'Changes saved successfully.', variant: 'success' });
  const showError = () =>
    toastRef.current?.show({ message: 'Something went wrong.', variant: 'error' });

  return (
    <>
      <Toast ref={toastRef} position="top-right" />
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        <Button variant="primary" onClick={showSuccess}>Success</Button>
        <Button variant="secondary" onClick={showError}>Error</Button>
      </div>
    </>
  );
}

API

duration number 4000
Time in milliseconds before a toast auto-dismisses. Applies as the default for every show() call but can be overridden per-toast via the duration option in the show() payload. Set to 0 to disable auto-dismiss entirely, requiring the user to click the close button.
max-visible number 3
Maximum toasts on screen at once (attribute: max-visible). Further show() calls queue FIFO and release as visible toasts dismiss. Set to 0 for no cap.
position 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center' 'top-right'
Anchors the toast stack to a fixed edge of the viewport. Top-right is the most conventional position for web applications. Bottom positions work well for media players or editors where the top area is occupied by toolbars.
dedupe boolean true
When true, a show() whose message and variant match a visible or queued toast is coalesced: the existing toast gains a "(×N)" counter and a fresh timer instead of a second toast appearing. Set the property to false from JS to disable.
queueLimit number 20
Maximum queued (not visible) toasts (attribute: queue-limit). Beyond it the oldest queued entries are dropped and arc-queue-overflow fires with the drop count.

Methods

show(options?) options?: { id?: number|string, message?: string, variant?: 'info' | 'success' | 'warning' | 'error', duration?: number, persistent?: boolean, progress?: number, action?: () => void, actionLabel?: string, onCancel?: () => void } number|string
Show a toast, or coalesce it into an identical one that is already showing. Passing progress puts the toast in progress mode, absorbed from arc-progress-toast in 4.2: it renders a track beneath the message, exempts itself from dedupe and from the auto-dismiss timer, and — given onCancel — offers a cancel button that fires arc-cancel. Move the bar with updateToast(id, { progress }) and end it with complete(id), which fires arc-complete. The mode is chosen here and is not switchable afterwards: a track appearing mid-life would relayout a notification the reader is already reading. action and actionLabel arrive from arc-snackbar the same way. The label renders a ghost button; a click runs the callback and fires arc-action before the toast dismisses.
dismiss(id) id: number|string
Dismiss a toast by the id show() returned, whether it is visible or still queued. Unknown ids are ignored.
clear()
Dismiss everything on screen and discard the queue.
updateToast(id, changes) id: number|string, changes: { progress?: number, message?: string }
Move a progress toast's bar, its message, or both. Unknown ids are ignored, matching dismiss(). Named updateToast rather than update because update is Lit's — the name arc-progress-toast used, and the reason it also carried a do-nothing update(changedProps) { super.update(changedProps); } override that read as if it meant something.
complete(id) id: number|string
Finish a progress toast: dismiss it and fire arc-complete. Distinct from dismiss() on purpose — the operation finishing and the user closing the toast are different events, and a consumer waiting on the first should not be woken by the second.

Events

arc-queue-overflow
Fired when the queue exceeds queueLimit and the oldest queued entries are dropped. detail: { dropped }.
arc-queue-change
Fired whenever the visible or queued count changes. detail: { visible, queued }.
arc-complete
Fired when a progress toast is completed with complete(id). detail: { id }.
arc-cancel
Fired when the user clicks a progress toast's cancel button. detail: { id }.
arc-action
Fired when the user clicks a toast's action button, before it dismisses. detail: { id }. Absorbed from arc-snackbar, whose action was reachable as an event as well as the action callback — a callback cannot be attached declaratively.
arc-close
Fired when a toast notification is dismissed. detail: { id } — the id show() returned.

See Also