New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@opentui-ui/toast

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@opentui-ui/toast

A beautiful toast library for terminal UIs built on OpenTUI

latest
Source
npmnpm
Version
0.0.5
Version published
Maintainers
1
Created
Source

A beautiful toast library for terminal UIs built on OpenTUI
Built by Matt Simpson | Inspired by Sonner

Installation

bun add @opentui-ui/toast

Quick Start

import { toast, ToasterRenderable } from "@opentui-ui/toast";

// 1. Add the toaster to your app (one line!)
ctx.root.add(new ToasterRenderable(ctx));

// 2. Show toasts from anywhere!
toast("Hello World");

That's it! No providers, no context, no configuration required.

Quick Reference

// Toast Types
toast("message");           // default
toast.success("message");   // green checkmark
toast.error("message");     // red X
toast.warning("message");   // yellow warning
toast.info("message");      // blue info
toast.loading("message");   // animated spinner

// Common Patterns
toast("msg", { description: "details" }); // Two-line toast
toast("msg", { duration: Infinity });     // Persistent (manual dismiss)
toast("msg", { action: { label: "Undo", onClick: fn } }); // With button

// Dismiss
const id = toast("Hello");
toast.dismiss(id);  // Dismiss one
toast.dismiss();    // Dismiss all

// Update existing toast
const id = toast.loading("Uploading...");
toast.success("Done!", { id }); // Updates in place

Toast Types

toast("Default notification");
toast.success("Operation completed!");
toast.error("Something went wrong");
toast.warning("Please check your input");
toast.info("Did you know?");
toast.loading("Processing...");

With Descriptions

toast.success("File uploaded", {
  description: "Your file has been saved to the cloud",
});

Promise Toast

The toast.promise() API automatically shows loading, success, and error states:

toast.promise(fetchData(), {
  loading: "Fetching data...",
  success: "Data loaded successfully!",
  error: "Failed to load data",
});

// With dynamic messages
toast.promise(saveUser(data), {
  loading: "Saving user...",
  success: (user) => `${user.name} has been saved`,
  error: (err) => `Error: ${err.message}`,
});

Actions

Add interactive buttons to your toasts:

toast("File deleted", {
  action: {
    label: "Undo",
    onClick: () => restoreFile(),
  },
});

Updating Toasts

Update an existing toast by passing its ID:

const id = toast.loading("Uploading...");

// Later...
toast.success("Upload complete!", { id });

// Or on error
toast.error("Upload failed", { id });

Dismissing Toasts

// Dismiss a specific toast
const id = toast("Hello");
toast.dismiss(id);

// Dismiss all toasts
toast.dismiss();

Duration

Duration Presets

Use the built-in TOAST_DURATION presets for consistent, readable duration values:

import { toast, TOAST_DURATION } from "@opentui-ui/toast";

// Quick confirmation (2s)
toast.success("Copied!", { duration: TOAST_DURATION.SHORT });

// Standard duration (4s) - this is the default
toast("Hello", { duration: TOAST_DURATION.DEFAULT });

// Important message (6s)
toast.warning("Check your settings", { duration: TOAST_DURATION.LONG });

// Critical information (10s)
toast.error("Connection lost", { duration: TOAST_DURATION.EXTENDED });

// Manual dismiss only
toast.info("Click to continue", { duration: TOAST_DURATION.PERSISTENT });

Duration Preset Values

PresetDurationUse Case
SHORT2000msBrief confirmations
DEFAULT4000msStandard notifications
LONG6000msImportant messages
EXTENDED10000msCritical information
PERSISTENTInfinityRequires manual dismissal

Custom Duration

You can also pass any number in milliseconds:

// Custom duration (in milliseconds)
toast("This disappears in 10 seconds", {
  duration: 10000,
});

// Persistent toast (won't auto-dismiss)
toast("I'll stay until dismissed", {
  duration: Infinity,
});

Themes

Optional theme presets are available via a separate import. These override the built-in defaults with alternative visual styles.

import { ToasterRenderable } from "@opentui-ui/toast";
import { minimal } from "@opentui-ui/toast/themes";

const toaster = new ToasterRenderable(ctx, minimal);

Available Themes

ThemeDescription
minimalClean and unobtrusive, no borders
monochromeGrayscale only, no colors

Customizing Themes

Spread a theme and override specific options:

import { minimal } from "@opentui-ui/toast/themes";

const toaster = new ToasterRenderable(ctx, {
  ...minimal,
  position: "bottom-right",
  stackingMode: "stack",
});

Theme Utilities

import { themes } from "@opentui-ui/toast/themes";

// Access all themes
themes.minimal;
themes.monochrome;

Theme Types

import type { ToasterTheme } from "@opentui-ui/toast/themes";

Toaster Configuration

Customize the toaster appearance and behavior:

const toaster = new ToasterRenderable(ctx, {
  // Position on screen
  position: "bottom-right", // 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'

  // Gap between toasts (terminal rows)
  gap: 1,

  // How to handle multiple toasts
  stackingMode: "single", // 'single' | 'stack'

  // Max visible toasts in stack mode
  visibleToasts: 3,

  // Show close button on toasts
  closeButton: false,

  // Maximum width for toasts
  maxWidth: 60,

  // Offset from screen edges
  offset: {
    top: 1,
    right: 2,
    bottom: 1,
    left: 2,
  },

  // Custom icons
  icons: {
    success: "✓",
    error: "✗",
    warning: "⚠",
    info: "ℹ",
    loading: "◌",
    close: "×",
  },

  // Toast styling and duration options
  toastOptions: {
    style: {
      /* base styles */
    },
    duration: 4000,
    success: {
      style: {
        /* overrides */
      },
      duration: 3000,
    },
    // ... other types
  },
});

ToasterOptions Reference

OptionTypeDefaultDescription
positionPosition"bottom-right"Position on screen
gapnumber1Gap between toasts (terminal rows)
stackingModeStackingMode"single"How to handle multiple toasts: "single" or "stack"
visibleToastsnumber3Max visible toasts in stack mode
closeButtonbooleanfalseShow close button on toasts
maxWidthnumber60Maximum width for toasts (terminal columns)
offsetToasterOffset{ top: 1, right: 2, bottom: 1, left: 2 }Offset from screen edges
iconsPartial<ToastIcons> | false-Custom icons for each toast type, or false to disable
toastOptionsToastOptions-Default toast options (styles, duration, per-type overrides)

Styling

Configure toast styles using the toastOptions prop:

const toaster = new ToasterRenderable(ctx, {
  toastOptions: {
    // Base styles applied to all toasts
    style: {
      backgroundColor: "#1a1a1a",
      foregroundColor: "#ffffff",
      borderColor: "#333333",
      borderStyle: "rounded", // 'single' | 'double' | 'rounded' | 'heavy'
      paddingX: 1,
      paddingY: 0,
    },
    // Default duration for all toasts
    duration: 4000,
    // Per-type overrides
    success: {
      style: { borderColor: "#22c55e" },
      duration: 3000,
    },
    error: {
      style: { borderColor: "#ef4444" },
      duration: 6000,
    },
    warning: {
      style: { borderColor: "#f59e0b" },
    },
    info: {
      style: { borderColor: "#3b82f6" },
    },
    loading: {
      style: { borderColor: "#6b7280" },
    },
  },
});

ToastStyle Reference

PropertyTypeDefaultDescription
borderboolean | BorderSides[]trueBorder configuration. true = all sides, false = none, or array like ["left", "right"]
borderColorstring"#333333"Border color (hex, rgb, or named)
borderStyleBorderStyle"single"Border style: "single" | "double" | "rounded" | "heavy"
customBorderCharsBorderCharacters-Custom border characters (overrides borderStyle)
minHeightnumber3Minimum height in terminal rows
maxWidthnumber-Maximum width in terminal columns
minWidthnumber-Minimum width in terminal columns
paddingnumber-Uniform padding (all sides)
paddingXnumber1Horizontal padding (left + right)
paddingYnumber0Vertical padding (top + bottom)
paddingTopnumber-Top padding
paddingBottomnumber-Bottom padding
paddingLeftnumber-Left padding
paddingRightnumber-Right padding
backgroundColorstring"#1a1a1a"Background color
foregroundColorstring"#ffffff"Text/foreground color
mutedColorstring"#6b7280"Muted text color (for descriptions)
iconColorstring-Icon color (defaults to borderColor)

Custom Border Characters

For full control over border rendering, use customBorderChars to define each border character:

const toaster = new ToasterRenderable(ctx, {
  toastOptions: {
    style: {
      border: ["left", "right"],
      customBorderChars: {
        topLeft: "",
        topRight: "",
        bottomLeft: "",
        bottomRight: "",
        horizontal: " ",
        vertical: "┃",
        topT: "",
        bottomT: "",
        leftT: "",
        rightT: "",
        cross: "",
      },
    },
  },
});

This is useful for creating unique border styles, like a vertical bar accent:

// Vertical bar on left and right only
border: ["left", "right"],
customBorderChars: {
  vertical: "┃",
  // Other characters can be empty strings
  topLeft: "", topRight: "", bottomLeft: "", bottomRight: "",
  horizontal: " ", topT: "", bottomT: "", leftT: "", rightT: "", cross: "",
},

Per-Toast Styles

Override styles on individual toasts:

toast.success("Custom styled!", {
  style: {
    borderColor: "#8b5cf6",
    backgroundColor: "#1e1b4b",
  },
});

Icon Sets

Choose from built-in icon sets based on terminal capabilities:

import {
  DEFAULT_ICONS, // Unicode icons (default)
  ASCII_ICONS, // ASCII-only for limited terminals
  MINIMAL_ICONS, // Single character icons
  EMOJI_ICONS, // Emoji icons
} from "@opentui-ui/toast";

// Use ASCII icons for terminals with limited Unicode support
const toaster = new ToasterRenderable(ctx, {
  icons: ASCII_ICONS,
});

// Use emoji icons for terminals with good emoji support
const toaster = new ToasterRenderable(ctx, {
  icons: EMOJI_ICONS,
});

Custom Loading Spinner

The loading icon can be either a static string or an animated spinner configuration:

const toaster = new ToasterRenderable(ctx, {
  icons: {
    // Static loading icon (no animation)
    loading: "...",

    // Or animated spinner
    loading: {
      frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
      interval: 80,
    },
  },
});

Some spinner examples:

// Dots spinner
{ frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"], interval: 80 }

// Circle spinner (default)
{ frames: ["◜", "◠", "◝", "◞", "◡", "◟"], interval: 100 }

// Simple ASCII spinner
{ frames: ["-", "\\", "|", "/"], interval: 100 }

// Bouncing bar
{ frames: ["[    ]", "[=   ]", "[==  ]", "[=== ]", "[ ===]", "[  ==]", "[   =]", "[    ]"], interval: 120 }

Disabling Icons

To disable icons entirely, set icons: false:

const toaster = new ToasterRenderable(ctx, {
  icons: false,
});

Individual toasts can still override this by providing a custom icon:

// Icons are disabled globally, but this toast will show a custom icon
toast.success("Done!", { icon: "✓" });

API Reference

toast(message, options?)

Show a default toast.

toast.success(message, options?)

Show a success toast with a checkmark icon.

toast.error(message, options?)

Show an error toast with an X icon.

toast.warning(message, options?)

Show a warning toast with a warning icon.

toast.info(message, options?)

Show an info toast with an info icon.

toast.loading(message, options?)

Show a loading toast with an animated spinner.

toast.promise(promise, options)

Show a toast that updates based on promise state.

toast.dismiss(id?)

Dismiss a specific toast by ID, or all toasts if no ID provided.

toast.getToasts()

Get all currently active toasts.

toast.getHistory()

Get all toasts ever created (including dismissed).

Toast Options

OptionTypeDefaultDescription
idstring | numberautoUnique identifier for the toast
descriptionstring | (() => string)-Secondary text below the title
durationnumber4000Time in ms before auto-dismiss
dismissiblebooleantrueWhether the toast can be dismissed
iconstringtype-basedCustom icon to display
action{ label, onClick }-Action button configuration
closeButtonbooleanfalseShow close button
styleToastStyle-Per-toast style overrides
onDismiss(toast) => void-Callback when dismissed
onAutoClose(toast) => void-Callback when auto-closed

Examples

Basic Example

import { createCliRenderer } from "@opentui/core";
import { toast, ToasterRenderable } from "@opentui-ui/toast";

const renderer = await createCliRenderer();

// Add toaster
const toaster = new ToasterRenderable(renderer, {
  position: "bottom-right",
});
renderer.root.add(toaster);

// Show some toasts
toast.success("Application started!");

setTimeout(() => {
  toast.info("Press 'q' to quit");
}, 1000);

Async Operation

async function saveData(data: unknown) {
  toast.promise(
    fetch("/api/save", {
      method: "POST",
      body: JSON.stringify(data),
    }),
    {
      loading: "Saving...",
      success: "Saved!",
      error: "Failed to save",
    }
  );
}

Manual Loading State

async function uploadFile(file: File) {
  const id = toast.loading("Uploading...");

  try {
    const result = await upload(file);
    toast.success(`Uploaded ${result.filename}`, { id });
  } catch (error) {
    toast.error("Upload failed", { id });
  }
}

React

For React applications, use the Toaster component and useToasts hook:

import { Toaster, useToasts, toast } from "@opentui-ui/toast/react";

function App() {
  return (
    <>
      <Toaster position="bottom-right" />
      <MyComponent />
    </>
  );
}

function MyComponent() {
  const { toasts } = useToasts();

  useKeyboard((key) => {
    if (key.name === "1") {
      toast.success("Hello World");
    }
  });

  return (
    <box>
      <text>Active toasts: {toasts.length}</text>
    </box>
  );
}

The useToasts hook provides reactive access to the current toast state, re-rendering your component whenever toasts are added, updated, or dismissed.

Solid

For Solid applications, use the Toaster component and useToasts hook:

import { Toaster, useToasts, toast } from "@opentui-ui/toast/solid";

function App() {
  return (
    <>
      <Toaster position="bottom-right" />
      <MyComponent />
    </>
  );
}

function MyComponent() {
  const toasts = useToasts();

  useKeyboard((key) => {
    if (key.name === "1") {
      toast.success("Hello World");
    }
  });

  return (
    <box>
      <text>Active toasts: {toasts().length}</text>
    </box>
  );
}

The useToasts hook returns a reactive accessor that updates whenever toasts change. Call it as a function (toasts()) to access the current array.

TypeScript

Full TypeScript support with exported types:

import type {
  Action,           // Action button configuration
  ExternalToast,    // Options for toast() calls
  Position,         // Toaster position type
  PromiseData,      // Configuration for toast.promise()
  SpinnerConfig,    // Animated spinner configuration { frames, interval }
  StackingMode,     // Stacking mode ('single' | 'stack')
  ToasterOffset,    // Offset configuration for positioning
  ToasterOptions,   // Configuration for ToasterRenderable
  ToastIcons,       // Custom icon set type
  ToastOptions,     // Default toast options (styles, duration, per-type overrides)
  ToastStyle,       // Per-toast styling options
  ToastType,        // Toast type variants
  TypeToastOptions, // Per-type options (style + duration)
} from "@opentui-ui/toast";

// Border types (for customBorderChars) come from @opentui/core
import type { BorderCharacters, BorderSides, BorderStyle } from "@opentui/core";

// Type guards
import { isAction, isSpinnerConfig } from "@opentui-ui/toast";

Constants

import { TOAST_DURATION } from "@opentui-ui/toast";

// Duration presets
TOAST_DURATION.SHORT;      // 2000ms - brief confirmations
TOAST_DURATION.DEFAULT;    // 4000ms - standard notifications
TOAST_DURATION.LONG;       // 6000ms - important messages
TOAST_DURATION.EXTENDED;   // 10000ms - critical information
TOAST_DURATION.PERSISTENT; // Infinity - manual dismiss only

Acknowledgments

Inspired by Sonner by Emil Kowalski.

License

MIT

Keywords

toast

FAQs

Package last updated on 01 Jan 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts