Skip to content

Toast ​

<ore-toast> is a declarative notification host. It renders the notification store for its scope; application code always creates, updates, and dismisses notifications through a toast service.

Basic Usage ​

Place a host once, then use the singleton service:

PreviewCode
RTL
html
<ore-toast position="bottom-right"></ore-toast>

<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
  <ore-button id="btn-basic" color="primary">Show Toast</ore-button>
</div>

<script type="module">
  import { toast } from '@vielzeug/refine/toast';

  document.getElementById('btn-basic').addEventListener('click', () => {
    toast.success('Changes saved successfully!');
  });
</script>

If no host exists, the service creates one in document.body on first use. The host is intentionally render-only: it has no add, update, dismiss, or clear methods.

Colors & Types ​

Use semantic color shortcuts to communicate outcome and intent.

PreviewCode
RTL
html
<ore-toast position="bottom-right"></ore-toast>

<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
  <ore-button id="btn-success" color="success">Success</ore-button>
  <ore-button id="btn-info" color="info">Info</ore-button>
  <ore-button id="btn-warning" color="warning">Warning</ore-button>
  <ore-button id="btn-error" color="error">Error</ore-button>
</div>

<script type="module">
  import { toast } from '@vielzeug/refine/toast';

  document.getElementById('btn-success').addEventListener('click', () => {
    toast.success('Profile updated successfully.');
  });
  document.getElementById('btn-info').addEventListener('click', () => {
    toast.info('A new update is available.');
  });
  document.getElementById('btn-warning').addEventListener('click', () => {
    toast.warning('Your session will expire in 5 minutes.');
  });
  document.getElementById('btn-error').addEventListener('click', () => {
    toast.error('Failed to save changes. Please try again.');
  });
</script>

Heading & Metadata ​

Add a heading and meta (such as a timestamp) to provide structured context.

PreviewCode
RTL
html
<ore-toast position="bottom-right"></ore-toast>

<ore-button id="btn-heading" color="primary">Show Detailed Toast</ore-button>

<script type="module">
  import { toast } from '@vielzeug/refine/toast';

  document.getElementById('btn-heading').addEventListener('click', () => {
    toast.add({
      color: 'success',
      heading: 'Deployment Successful',
      message: 'Production build v2.4.0 is now live.',
      meta: 'Just now',
    });
  });
</script>

Action Buttons ​

Attach interactive action buttons that execute callbacks before dismissing.

PreviewCode
RTL
html
<ore-toast position="bottom-right"></ore-toast>

<ore-button id="btn-action" color="primary">Delete Item</ore-button>

<script type="module">
  import { toast } from '@vielzeug/refine/toast';

  document.getElementById('btn-action').addEventListener('click', () => {
    toast.add({
      actions: [
        {
          label: 'Undo',
          onClick: () => console.log('Action undone'),
        },
      ],
      color: 'info',
      heading: 'Item Deleted',
      message: 'The item has been moved to trash.',
    });
  });
</script>

Positions ​

Set position on <ore-toast> to control list placement (top-left, top-center, top-right, bottom-left, bottom-center, bottom-right).

PreviewCode
RTL
html
<ore-toast position="top-right"></ore-toast>

<ore-button id="btn-top-right" color="primary">Top Right Toast</ore-button>

<script type="module">
  import { toast } from '@vielzeug/refine/toast';

  document.getElementById('btn-top-right').addEventListener('click', () => {
    toast.info('Notification anchored at top-right.');
  });
</script>

Variants ​

Toasts support solid (default), flat, and bordered visual variants.

PreviewCode
RTL
html
<ore-toast position="bottom-right"></ore-toast>

<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
  <ore-button id="btn-solid" variant="solid" color="primary">Solid</ore-button>
  <ore-button id="btn-flat" variant="flat" color="primary">Flat</ore-button>
  <ore-button id="btn-bordered" variant="bordered" color="primary">Bordered</ore-button>
</div>

<script type="module">
  import { toast } from '@vielzeug/refine/toast';

  document.getElementById('btn-solid').addEventListener('click', () => {
    toast.add({ color: 'primary', message: 'Solid variant notification', variant: 'solid' });
  });
  document.getElementById('btn-flat').addEventListener('click', () => {
    toast.add({ color: 'primary', message: 'Flat variant notification', variant: 'flat' });
  });
  document.getElementById('btn-bordered').addEventListener('click', () => {
    toast.add({ color: 'primary', message: 'Bordered variant notification', variant: 'bordered' });
  });
</script>

Toast service ​

The toast singleton owns notification state, timers, lifecycle, and mutations.

ts
import { toast } from '@vielzeug/refine/toast';

const id = toast.add({
  color: 'primary',
  duration: 0,
  dismissible: false,
  message: 'Uploading file…',
});

toast.update(id, {
  color: 'success',
  duration: 3000,
  dismissible: true,
  message: 'Upload complete!',
});

toast.dismiss(id);
toast.clear();

Use the colour shortcuts for common notifications:

ts
toast.success('Profile saved');
toast.info('A new version is available');
toast.warning('Your session expires soon');
toast.error('Upload failed', { duration: 0 });

Promise helper ​

toast.promise() keeps a persistent loading notification and updates it when the promise settles.

ts
await toast.promise(uploadFile(), {
  loading: 'Uploading…',
  success: (url) => `Uploaded to ${url}`,
  error: (error) => `Upload failed: ${String(error)}`,
});

Scoped services ​

Create a scoped service for notifications inside a drawer, dialog, or application region. The service binds to the declarative host in that root, or lazily creates one there.

ts
import { createToastService } from '@vielzeug/refine/toast';

const drawerToast = createToastService(drawerElement);

drawerToast.configure({ max: 3, position: 'top-center' });
drawerToast.success('Saved inside the drawer');

// Dispose a scoped service when its owning region is permanently removed.
drawerToast.dispose();

Services created with the same root share one store. Different roots are isolated.

configure() applies immediately: position writes the host attribute, and max reaches the store through the host's own max watch. Calling it before the first notification simply configures the host that gets created lazily.

Observing transitions ​

tap() exposes add, dismiss, and dispose transitions as a side channel: for analytics, logging, or syncing notifications to storage. Handler errors are swallowed; observation never affects toast behavior.

ts
import { toast } from '@vielzeug/refine/toast';

const stop = toast.tap((event) => {
  if (event.type === 'add') console.log('shown', event.id);
  if (event.type === 'dismiss') console.log('removed', event.id);
});

stop(); // detach

Declarative host ​

Use attributes to set a host's placement and notification limit:

html
<ore-toast position="top-right" max="3"></ore-toast>
AttributeDefaultDescription
positionbottom-righttop-* or bottom-* list anchor
max5Maximum live notifications per scope: attribute changes apply live

Notification options ​

ts
toast.add({
  actions: [{ label: 'Undo', onClick: undo }],
  color: 'success',
  heading: 'Message sent',
  message: 'Your message was delivered.',
  meta: 'Just now',
  duration: 5000,
});
OptionDefaultDescription
messageN/ARequired notification text
idgeneratedStable notification identifier
colorprimaryAlert colour theme
headingN/AAlert heading
variantsolidsolid, flat, or bordered
duration5000; 0 for action toastsAuto-dismiss delay in milliseconds; 0 keeps it visible. Entries carrying actions persist until dismissed by default: keyboard and screen-reader users reach toasts last in tab order, so a timed expiry would expire the choice unseen
dismissibletrueShows the close button
snackbarfalseMaterial-style compact bar: inverted neutral surface, single-row padding, text-style actions; overrides variant
actionsN/AButtons (flat by default, ghost when snackbar) that run onClick then dismiss
replacefalseReplace a live entry with the same message instead of stacking a duplicate
urgencyderivedpolite or assertive; errors are assertive by default
onDismissN/ACalled after the exit animation completes

toast.update(id, changes) patches only the provided fields: omitted ones leave the entry (and its timer) unchanged.

Snackbar ​

Set snackbar: true for small, transient confirmations: a Material-style bar on an inverted surface (dark chip in light themes, light chip in dark themes) with single-row padding and a flat text action. The bar sizes to its content up to the host's width cap, staying flush with the position's anchored edge. With an action it persists until dismissed (the default for action toasts), and on phones the action stacks below a wrapped message:

ts
toast.add({
  actions: [{ label: 'Undo', onClick: undo }],
  horizontal: true,
  message: 'Damage +1',
  snackbar: true,
});

Behavior and accessibility ​

Notifications render as a vertical list anchored to the host position: newest nearest the anchored edge, so every notification stays readable and reachable with a pointer, touch, or keyboard. Each notification is announced once through the host's polite or assertive live region; the embedded alert itself carries no live-region semantics.

Timed notifications show a thin progress bar along the bottom edge. Hovering or focusing the list pauses auto-dismiss timers and the bar; leaving resumes the remaining duration. Timers also pause while a top-layer surface (an open dialog, fullscreen) covers the toasts: the user cannot interact with them, so choices never expire unseen.

Users can dismiss closable notifications with the close button, a horizontal swipe, or the Escape key. Escape dismisses the notification holding focus; pressed anywhere else it dismisses the newest dismissible notification, unless an open top-layer surface owns the key. When a removed notification held focus, focus returns to the element focused before it, so keyboard users keep their place instead of restarting from the document top.

Notifications fade and slide in and out; both transitions honour prefers-reduced-motion, which also hides the progress bar. Removal happens on a fixed store-owned timeout (~250ms after dismissal), so a themed --toast-exit-duration beyond the default 200ms is clipped. On narrow viewports (≤ 480px) notifications span the full width above the safe-area inset, and horizontal snackbars stack their action below a wrapped message.

Flat and bordered notifications use an opaque surface (--toast-bg) tinted with the notification colour so they never blend into the page beneath them. Multiple notifications exit independently, and all timers and subscriptions are cleaned up when a scoped service is disposed.

CSS custom properties ​

PropertyDescriptionDefault
--toast-max-widthNotification width cap (full width on phones)400px
--toast-gapGap between notificationsvar(--size-2)
--toast-bgOpaque surface for flat and bordered notificationsTinted var(--color-contrast-50)
--toast-snackbar-bgSnackbar surfacevar(--color-contrast-900)
--toast-snackbar-colorSnackbar text colourvar(--color-contrast-100)
--toast-snackbar-paddingSnackbar paddingvar(--size-2) var(--size-4)
--toast-snackbar-shadowSnackbar elevation shadowvar(--shadow-lg)
--toast-shadowElevation shadowvar(--shadow-xl)
--toast-enter-duration / --toast-exit-durationMotion durationsvar(--duration-200)
--toast-progress-heightHeight of the auto-dismiss progress bar3px
--toast-progress-colorColour of the auto-dismiss progress barNotification colour
--toast-inset-top / --toast-inset-bottom / --toast-inset-left / --toast-inset-rightViewport insetsvar(--size-4)
--toast-z-indexStacking ordervar(--z-toast)

CSS parts ​

PartDescription
containerNotification list
toast-wrapperPer-notification layout wrapper (swipe target)
toast-innerPer-notification motion target
progressAuto-dismiss progress bar