npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@onedevio/og-toast

v1.0.0

Published

Accessible, signal-based toast notifications for Angular 20.

Downloads

78

Readme

og-toast

Accessible, signal-based toast notifications for Angular 20.

  • Standalone — one component, one service, no NgModule required.
  • Signal state — works in zone-based and zoneless applications.
  • Multi-position stacks — every toast picks its own corner; stacks are grouped automatically.
  • Rich content — title/message, inline action buttons, your own template, or your own component.
  • Async awareloading toasts, update(), and promise() for one-line async feedback.
  • Swipe to dismiss — drag or flick a toast towards its screen edge, on touch, pen or mouse.
  • Accessible — live-region roles, keyboard dismissal, focus styles, prefers-reduced-motion.
  • Themeable — every colour, size and timing is a CSS custom property.
  • SSR-safe — no timers are scheduled on the server.
  • Zero runtime dependencies beyond @angular/core and @angular/common.

Installation

npm install @onedevio/og-toast

Quick start

Render the container once, near the root of the app:

import { Component, inject } from '@angular/core';
import { OgToastComponent, OgToastService } from '@onedevio/og-toast';

@Component({
  selector: 'app-root',
  imports: [OgToastComponent],
  template: `
    <router-outlet />
    <og-toast />
  `,
})
export class App {
  private readonly toast = inject(OgToastService);

  save(): void {
    this.toast.success('Your changes have been published.', 'Saved');
  }
}

That is all that is required — OgToastService is providedIn: 'root' and falls back to sensible defaults.

Configuration

Override the defaults once, at bootstrap:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideOgToast } from '@onedevio/og-toast';

bootstrapApplication(App, {
  providers: [
    provideOgToast({
      position: 'bottom-center',
      duration: 5000,
      maxToasts: 3,
      showProgress: true,
      preventDuplicates: true,
    }),
  ],
});

| Option | Type | Default | Description | | ----------------------- | ---------------------------------- | ------------------------ | -------------------------------------------------------------------------------- | | position | OgToastPositionInput | 'top-right' | Default viewport anchor. Accepts 'top-right' or { vertical, horizontal }. | | duration | number | 4000 | Auto-dismiss delay in ms. 0 keeps the toast until dismissed. | | maxToasts | number | 5 | Maximum toasts on screen; the oldest is dismissed first. 0 disables the limit. | | dismissible | boolean | true | Clicking the toast body dismisses it. | | closable | boolean | true | Render the close button. | | pauseOnHover | boolean | true | Hover or focus pauses the auto-dismiss timer. | | showIcon | boolean | true | Render the type icon. | | showProgress | boolean | false | Render a progress bar for the remaining time. | | ariaLive | 'polite' \| 'assertive' \| 'off' | 'polite' | Announcement politeness; errors always default to 'assertive'. | | preventDuplicates | boolean | false | Restart the existing toast instead of stacking an identical one. | | newestOnTop | boolean | false | Insert new toasts nearest the viewport edge. | | exitAnimationDuration | number | 200 | Leave-animation length; keep in sync with --og-toast-exit-duration. | | ariaLabel | string | 'Notifications' | Accessible label of the toast region. | | closeAriaLabel | string | 'Dismiss notification' | Accessible label of the close button. |

Everything except maxToasts, preventDuplicates, newestOnTop, exitAnimationDuration, swipeThreshold and the two labels can also be set per toast.

Service API

success(message, title?, options?): OgToastRef;
error(message, title?, options?): OgToastRef;
warning(message, title?, options?): OgToastRef;
info(message, title?, options?): OgToastRef;
loading(message, title?, options?): OgToastRef;   // sticky until updated or dismissed

show(config: OgToastConfig): OgToastRef;          // full control
promise(source, messages, options?): OgToastRef;  // loading → success/error
update(id: string, changes: OgToastUpdate): void;
invokeAction(id: string): void;

dismiss(id: string, reason?): void;               // animates the toast out
dismissAll(reason?): void;
clear(): void;                                    // removes everything immediately
getRef(id: string): OgToastRef | undefined;

readonly toasts: Signal<readonly OgToast[]>;
readonly groups: Signal<readonly OgToastGroup[]>;
readonly count: Signal<number>;
readonly exiting: Signal<ReadonlySet<string>>;
readonly paused: Signal<ReadonlySet<string>>;

The third argument of the helpers is either a duration in milliseconds or a full options object:

toast.error('The upload failed.', 'Error', 8000);

toast.info('Deploy started.', undefined, {
  duration: 0, // sticky until dismissed
  position: 'bottom-left',
  dismissible: false,
  showProgress: true,
  cssClass: 'deploy-toast',
});

Toast references

Every open method returns an OgToastRef:

const ref = toast.loading('Uploading…');

ref.update({ type: 'success', message: 'Uploaded', duration: 3000 });
ref.pause();
ref.resume();
ref.dismiss();

ref.toast(); // Signal<OgToast | undefined> — undefined once removed
ref.dismissed(); // Signal<boolean>
await ref.afterDismissed(); // 'timeout' | 'user' | 'action' | 'programmatic' | 'limit' | 'clear'

update() leaves absent fields untouched. The content fields — title, message, action, template, component and data — can be blanked out by passing undefined explicitly.

Async feedback

toast.promise(api.save(draft), {
  loading: 'Saving…',
  success: (saved) => `Saved “${saved.title}”`,
  error: (err) => ({ title: 'Could not save', message: String(err) }),
});

A loading toast appears immediately and turns into a success or error toast when the promise settles. The promise itself is left untouched, so the caller stays responsible for handling its rejection.

Action buttons

toast.info('Draft moved to trash.', 'Deleted', {
  action: {
    label: 'Undo',
    handler: (ref) => restore(ref.id),
    dismissOnAction: true, // default
  },
});

Swipe to dismiss

Toasts can be flicked away with a pointer, travelling towards the edge they are anchored to: a top-right toast swipes right, bottom-left swipes left, and a centred stack swipes up or down. A drag dismisses once it passes swipeThreshold, or earlier if it is fast enough to read as a flick.

provideOgToast({ swipeToDismiss: true, swipeThreshold: 100 });

toast.error('Payment declined.', 'Error', { swipeToDismiss: false }); // must be acknowledged

The gesture pauses the auto-dismiss timer while the pointer is down, claims only the axis it needs (touch-action: pan-y for a horizontal swipe, so the page still scrolls), never fires a stray click on release, and reports 'swipe' to afterDismissed().

Custom content

Render your own template:

<ng-template #release let-toast let-ref="ref" let-data="data">
  <p>Release {{ data.version }} is live</p>
  <button type="button" (click)="ref.dismiss()">Got it</button>
</ng-template>
toast.show({ type: 'info', template: this.release(), data: { version: '2.4.0' } });

…or your own component, which can read its payload and drive its own toast:

@Component({/* … */})
export class InviteToast {
  protected readonly invite = injectOgToastData<Invite>();
  private readonly ref = inject(OG_TOAST_REF);

  accept(): void {
    this.ref.update({ type: 'success', component: undefined, message: 'Joined!' });
  }
}

toast.show({ type: 'info', component: InviteToast, data: invite, duration: 0 });

data is deliberately typed as unknown on the toast pipeline; injectOgToastData<T>() is where you name its type.

Theming

The component exposes CSS custom properties. Set them on og-toast, on :root, or on any ancestor:

og-toast {
  --og-toast-radius: 16px;
  --og-toast-max-width: 420px;
  --og-toast-inset: 32px;
  --og-toast-success-bg: #052e21;
  --og-toast-success-fg: #d1fae5;
  --og-toast-success-border: #34d399;
}

Available groups: layout (--og-toast-z-index, --og-toast-inset, --og-toast-gap, --og-toast-min-width, --og-toast-max-width, --og-toast-padding, --og-toast-radius), typography (--og-toast-font-family, --og-toast-title-size, --og-toast-message-size, --og-toast-icon-size), motion (--og-toast-enter-duration, --og-toast-exit-duration, --og-toast-enter-easing, --og-toast-exit-easing), elevation (--og-toast-shadow, --og-toast-shadow-hover), progress (--og-toast-progress-height, --og-toast-progress-opacity) and per type --og-toast-{success|error|warning|info|loading}-{bg|border|fg|icon}.

A dark palette is applied automatically under prefers-color-scheme: dark; overriding the variables yourself takes precedence.

Accessibility

  • Each stack is a role="region" labelled by ariaLabel.
  • ariaLive: 'assertive' renders role="alert", 'polite' renders role="status", 'off' renders neither. Errors default to assertive.
  • Dismissible toasts are focusable and respond to Enter, Space and Escape.
  • The close button and action button are real <button>s with accessible labels and visible focus rings.
  • Hover and keyboard focus pause the auto-dismiss timer, so toasts do not disappear mid-read.
  • Swipe is an addition to, never a replacement for, the close button and keyboard dismissal.
  • Animations collapse to a plain fade under prefers-reduced-motion: reduce.

Server-side rendering

The service detects a non-browser platform and skips all timers, so toasts created during SSR render once and never block hydration or leave pending macrotasks.

Package layout

| Export | Purpose | | ------------------------------------------------------ | --------------------------------------------------------------- | | OgToastComponent | The <og-toast /> container. Renders one region per position. | | OgToastItemComponent | A single toast. Presentational; exported for custom containers. | | OgToastIconComponent | The type glyph, including the loading spinner. | | OgToastService | Creates and tracks toasts. | | OgToastRef | Handle to one toast. | | provideOgToast / OG_TOAST_CONFIG | Application-wide defaults. | | OG_TOAST_REF / OG_TOAST_DATA / injectOgToastData | Injection surface for custom toast components. |

License

MIT