Toast

Brief, auto-dismissing notifications that stack in a corner of the screen.

import { ... } from '@corndev/ui-notifications'

HTML

<div class="corn-toast-container" data-position="top-right">
  <div class="corn-toast" data-type="success" data-visible role="status">
    <div class="corn-toast-content">
      <p class="corn-toast-title">Saved</p>
    </div>
    <button class="corn-toast-close" aria-label="Dismiss">&times;</button>
  </div>
</div>

Classes

Class
.corn-toast
.corn-toast-container
.corn-toast-icon
.corn-toast-content
.corn-toast-title
.corn-toast-message
.corn-toast-close
.corn-toast-progress

Attributes

OnAttributeValues
.corn-toast-containerdata-positiontop-right|top-left|top-center|bottom-right|bottom-left|bottom-center
.corn-toastdata-visiblepresent or absent
.corn-toastdata-leavingpresent or absent
.corn-toastdata-typesuccess|warning|danger|info|default

Vanilla JS

Required for behaviour — adds creates and stacks toasts, then removes them on a timer.

import { createToastManager } from '@corndev/ui-notifications';
import '@corndev/ui/theme';

const instance = createToastManager({ /* options */ });

Options

OptionTypeDefaultDescription
position'top-right'|'top-left'|'top-center'|'bottom-right'|'bottom-left'|'bottom-center''top-right'
maxToastsnumber5Max visible toasts before oldest is removed

React

NotificationProvider, useNotifications, notifications — from @corndev/ui-notifications-react.

The React props above belong to <NotificationProvider>, which wraps the app once. useNotifications() then returns { show, dismiss, dismissAll, update } — show(toastOpts) returns the toast id. There is no React component named Toast. The same four methods are also exported as notifications, a module-level object callable with no React context in scope — from a store, an event handler, or code that runs before the app renders; calls made before <NotificationProvider> mounts are queued and replayed in order. update(id, toastOpts) changes a toast in place, and a new duration restarts its timer, which is how a “Saving…” toast becomes “Saved”. The names match the hook and createToastManager.

The props are the same as the options above, plus className.

React usage

For React, use NotificationProvider and useNotifications — see the Alert page for the full setup guide. Toast types and options are the same.

import { useNotifications } from '@corndev/ui-notifications-react';

function SaveButton() {
  const { show } = useNotifications();
  return (
    <button onClick={() => show({ message: 'Saved!', type: 'success' })}>
      Save
    </button>
  );
}

Toast types

TypeDescription
defaultNeutral message
successPositive confirmation
warningCautionary alert
dangerError or destructive action
infoInformational message

Positions

PositionDescription
top-rightDefault
top-left
top-center
bottom-right
bottom-left
bottom-center

From outside React

Not every notification comes from a component. A store, an API client, an error handler or boot code has no hook to call — and that is where most of them come from in practice. The notifications object works anywhere:

import { notifications } from '@corndev/ui-notifications-react';

export async function saveDocument(doc) {
  try {
    await api.put(doc);
    notifications.show({ message: 'Saved', type: 'success' });
  } catch (error) {
    notifications.show({ message: error.message, type: 'danger', duration: 0 });
  }
}

It still needs <NotificationProvider> mounted once at the root — that is what renders the toasts. Calls made before it mounts are queued and replayed in order, so a notification fired during boot appears rather than vanishing.

show() returns the toast id even when the call is still queued, so you can always dismiss or update what you just asked for:

const id = notifications.show({ message: 'Uploading…', duration: 0 });

notifications.update(id, { message: 'Uploaded', type: 'success', duration: 4000 });
notifications.dismiss(id);
notifications.dismissAll();

update changes a toast in place. Giving it a new duration restarts the clock, which is what turns a pinned “Uploading…” into a “Uploaded” that fades on its own.

Which one should I use?

useNotifications()Inside a component. Re-renders with the provider, and reads naturally there.
notificationsEverywhere else — modules, stores, callbacks, boot code.
createToastManager()No React at all. The vanilla path, unchanged.

All three drive the same toasts, so mixing them is fine.

One vocabulary

The facade’s methods are dismiss and dismissAll, the same names as useNotifications() and createToastManager(). A toast’s appearance is its type: 'success' | 'warning' | 'danger' | 'info'.

Mount exactly one provider

Two <NotificationProvider>s render two sets of toasts for a single call. The facade warns in development if a second one mounts.