0.1.0-rc.2

Toast

Toasts surface brief, non-blocking feedback after an action, such as save confirmations, errors, or background sync status.

Try it

    Usage

    Mount RuiToaster once at the app root, then call toast() imperatively to show messages. Each call returns a toast id you can pass to toast.dismiss().

    import { RuiToaster, toast } from '@ecopages/radiant-ui/toast';
    import { RuiButton } from '@ecopages/radiant-ui/button';
     
    <RuiToaster position="bottom-end" duration={4000} />
    <RuiButton on:click={() => toast.success('Changes saved')}>
      Save
    </RuiButton>

    The imperative toast() helper is Sonner-shaped: toast(), toast.message(), toast.success(), toast.error(), toast.info(), toast.warning(), toast.loading(), toast.promise(), toast.dismiss(id?), and toast.clear().

    Match variant to message

    Use success for confirmations, error for failures, warning for caution, and info for neutral updates. loading shows a spinner and never auto-dismisses.

    toast.success('Changes saved');
    toast.error('Unable to reach the server', { description: 'Try again in a moment.' });
    toast.warning('Disk space is running low');
    toast.info('Your session will expire soon');

    Theming

    Toast variants reuse the semantic status roles from the active theme (the same info / success / warning / error families as alerts) via .rui-toast--* on the composed surface:

    variantSemantic roleTypical utilities on .rui-toast--*
    infoinfoborder-info/40, text-info
    successsuccessborder-success/40, text-success
    warningwarningborder-warning/40, text-warning
    errorerror (destructive)border-error/40, text-error
    loadingneutral surfaceborder-border, text-on-surface

    The surface stays bg-surface text-on-surface with a per-variant border and text accent, so toasts read as floating chrome rather than filled status blocks. Override roles at the theme layer (tokens/presets/colors/*.css), not in component CSS.

    Duration and dismissal

    Set duration per toast for urgent vs routine messages. Toasts pause their countdown while hovered, while a pointer is interacting, or while the tab is hidden, and resume from the remaining time.

    toast('Autosaved', { duration: 2000 });
    toast.error('Sync failed', { duration: 10_000, closeButton: true });

    Enable closeButton when users need time to read, or dismissible to allow swipe-to-dismiss. toast.promise() drives a single toast through loading → success/error:

    toast.promise(save(), {
      loading: 'Saving…',
      success: 'Saved',
      error: 'Save failed',
    });

    Stacking

    Toasts stack at the configured corner. By default the stack collapses behind the front toast (peek) and expands on hover; set expand to always show full gaps.

      <RuiToaster expand position="bottom-end" />

      visibleToasts caps how many stay mounted at once; older toasts wait in the queue.

      Position

      Place the stack at any corner or edge center.

        <RuiToaster position="top-center" />

        Accessibility

        • Toasts use role="status" for polite announcements that do not interrupt current tasks; the toaster wraps the stack in an aria-live="polite" region.
        • Error toasts use role="alert" semantics for immediate attention.
        • Do not rely on toasts alone for critical errors; pair with inline field errors when appropriate.
        • The stack region is focusable (tabindex="-1") so keyboard users can inspect messages; close controls are labeled buttons.

        Why a custom element?

        <rui-toast> owns dismiss lifetime bookkeeping (pause on hover / hidden tab, swipe-to-dismiss, and exit animation) which requires DOM state. <rui-toaster> owns the stack layout (peek/expand math, per-position filtering). The RuiToast / RuiToaster JSX helpers are thin passthroughs; the elements render their own composed light-DOM surface.

        API

        Imperative API

        The toast() callable and its variants accept (title, options?) where options is ToastOptions:

        OptionTypeDefaultDescription
        idstring | numberautoDismiss a specific toast by id.
        descriptionstringSupporting detail under the title.
        durationnumber4000Lifetime in ms; Infinity keeps it until dismissed.
        action{ label, onClick }Render an action button.
        dismissiblebooleantrueAllow close button / swipe-to-dismiss.
        closeButtonbooleantoaster defaultShow the corner close control.
        positionToastPositiontoaster defaultPer-toast placement override.

        <rui-toaster> attributes

        AttributeTypeDefaultDescription
        positiontop/bottom-start/center/endbottom-endCorner / edge placement.
        durationnumber4000Default lifetime in ms.
        visible-toastsnumber3Max toasts mounted at once; older wait in queue.
        close-buttonbooleanfalseShow a close button on every toast.
        expandbooleanfalseAlways render the stack expanded.
        gapnumber14Gap between expanded toasts in px.
        offsetnumber24Viewport inset in px.
        containerstring''CSS selector for a positioning root (docs canvas).

        <rui-toast> attributes

        Rendered by the toaster; listed for completeness. Documented via @attr on RuiToastElement.

        AttributeTypeDefaultDescription
        toast-idstring''Toast id for deadline bookkeeping.
        titlestring''Heading text.
        descriptionstring''Supporting detail.
        variantdefault · info · success · warning · error · loadingdefaultStatus tone.
        durationnumber4000Lifetime before auto-dismiss.
        dismissiblebooleantrueAllow close / swipe.
        close-buttonbooleanfalseCorner close control.
        action-labelstring''Action button text.
        positionToastPositionbottom-endPlacement; mirrors the toaster.
        marked-deletebooleanfalseMarks for animated exit.

        Events

        EventDetailDescription
        rui-toast-showToastShowDetailDocument-level; the toaster listens and creates a toast.
        rui-toast-dismiss{ id? }Document-level; the toaster dismisses the matching toast.
        rui-toast-mountedBubbles after a toast mounts and paints; the toaster resyncs stack layout.

        Use showToast() / dismissToast() to dispatch the document events, or the simpler toast() API.

        CSS classes

        Public BEM classes on the composed light-DOM surface (documented via @cssclass on the elements):

        ClassDescription
        .rui-toaster-regionAnnouncement region wrapper (display: contents).
        .rui-toasterThe <ol> stack list.
        .rui-toastToast surface (role="status").
        .rui-toast--infoInfo tone.
        .rui-toast--successSuccess tone.
        .rui-toast--warningWarning tone.
        .rui-toast--errorError tone.
        .rui-toast--loadingLoading tone.
        .rui-toast__iconStatus icon wrapper.
        .rui-toast__loaderSpinner for loading toasts.
        .rui-toast__contentTitle + description column.
        .rui-toast__titleHeading.
        .rui-toast__descriptionSupporting detail.
        .rui-toast__actionOptional action button.
        .rui-toast__closeCorner close control.

        Theme roles (per variant)

        VariantCSS variables consumed
        info--info
        success--success
        warning--warning
        error--error
        loading--border, --on-surface

        error is the destructive status role (same family as destructive buttons). Surface and text roles are --surface / --on-surface for all variants.