Skip to content

Guide Notification

MeowLynxSea edited this page Feb 18, 2026 · 4 revisions

NotificationCenter

A global notification manager that handles toast queuing, persistence, and callbacks.

The NotificationCenter provides a unified way to show toast notifications across your application with built-in queue management, auto-dismiss, persistence for sticky notifications, and interaction callbacks.

Related

  • For the basic toast visual component, see Toast
  • Demos - Complete working examples

When to use

  • You need to show notifications from anywhere in your application
  • You want automatic queue management (max 5 notifications by default)
  • You need persistence for important notifications that survive window refresh
  • You want click/dismiss callbacks for user interactions

Architecture

The notification system consists of three parts:

  1. NotificationCenter: Global state manager (registered as a GPUI global)
  2. NotificationHost: Overlay component that renders the toast stack
  3. Notification: The notification payload with message, kind, and options

Quick Start

Step 1: Add the host overlay

Render notification_host() once at the root of your window:

use yororen_ui::notification::notification_host;

div()
    .child(app_content)
    .child(notification_host())

Step 2: Push notifications

Push notifications from anywhere you have &mut gpui::App:

use yororen_ui::notification::{Notification, NotificationCenter};
use yororen_ui::component::ToastKind;

let center = cx.global::<NotificationCenter>().clone();
center.notify(
    Notification::new("Saved!")
        .kind(ToastKind::Success),
    cx,
);

Step 3: Initialize the center (optional)

If you need to configure the center before first use, initialize it in your app:

// In your app's render function
if cx.try_global::<NotificationCenter>().is_none() {
    cx.set_global(NotificationCenter::new());
}
let center = cx.global::<NotificationCenter>().clone();

Notification API

  • Notification::new("message"): constructor
  • .title("title"): optional title
  • .kind(ToastKind): notification type
    • Neutral | Success | Warning | Error | Info
  • .dismiss(DismissStrategy):
    • DismissStrategy::After { duration_ms: 4000 } (default: 4 seconds)
    • DismissStrategy::Manual: user must explicitly dismiss
  • .sticky(bool): persist across window refresh (default: false)
  • .payload(json_value): arbitrary data for callbacks
  • .action_label("label"): label shown for click action

NotificationCenter API

  • NotificationCenter::new(): constructor
  • .notify(notification, cx): push a notification, returns notification ID
  • .notify_with_callbacks(notification, on_click, on_dismiss, cx): push with callbacks
  • .dismiss(id, cx): dismiss a specific notification
  • .clear(cx): dismiss all notifications
  • .items(): get all current notifications
  • .set_max_queue_len(n) size (default:: set max queue 5)
  • .set_persistence(enabled, key): configure persistence

DismissStrategy

use yororen_ui::notification::DismissStrategy;

// Auto-dismiss after 4 seconds (default)
DismissStrategy::After { duration_ms: 4000 }

// Manual dismiss only
DismissStrategy::Manual

Persistence Behavior

  • Only notifications with sticky = true are persisted
  • Callbacks are not persisted (they are re-attached on load)
  • payload is persisted for sticky notifications
  • Persistence uses GPUI's keyed state system

Examples

Basic notification

use yororen_ui::notification::{Notification, NotificationCenter};
use yororen_ui::component::ToastKind;

center.notify(
    Notification::new("Operation completed")
        .kind(ToastKind::Success),
    cx,
);

Sticky notification (persists across window refresh)

use yororen_ui::notification::{Notification, DismissStrategy};

center.notify(
    Notification::new("Important: Long-running task")
        .kind(ToastKind::Info)
        .sticky(true)
        .dismiss(DismissStrategy::Manual),
    cx,
);

Notification with click callback

use std::sync::Arc;
use yororen_ui::notification::{Notification, NotificationCenter};

center.notify_with_callbacks(
    Notification::new("Click to view details")
        .kind(ToastKind::Info)
        .action_label("View")
        .payload(json!({ "id": 42 })),
    Some(Arc::new(|notification, event, window, cx| {
        // Handle click - notification.payload contains the data
        println!("Clicked: {:?}", notification.payload);
    })),
    None, // on_dismiss callback
    cx,
);

Custom queue length

center.set_max_queue_len(10);

Disable persistence

center.set_persistence(false, "my-key");

NotificationHost API

  • notification_host(): constructor
  • .max_width(px(...)): max toast width (default: 420px)
  • .offset(px(...)): offset from corner (default: 16px)
use yororen_ui::notification::notification_host;
use gpui::px;

div()
    .child(content)
    .child(
        notification_host()
            .max_width(px(360.))
            .offset(px(24.))
    )

Full Example

use std::sync::Arc;
use gpui::{Context, Render, Window, IntoElement, ParentElement, Styled};
use yororen_ui::notification::{
    Notification, NotificationCenter, DismissStrategy, notification_host
};
use yororen_ui::component::{button, ToastKind};

struct MyApp;

impl Render for MyApp {
    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        // Initialize center if needed
        if cx.try_global::<NotificationCenter>().is_none() {
            cx.set_global(NotificationCenter::new());
        }
        let center = cx.global::<NotificationCenter>().clone();

        div()
            .size_full()
            .child(
                button("demo:notify")
                    .child("Show Notification")
                    .on_click({
                        let center = center.clone();
                        move |_ev, _window, cx| {
                            center.notify(
                                Notification::new("Hello from NotificationCenter!")
                                    .kind(ToastKind::Success)
                                    .dismiss(DismissStrategy::After { duration_ms: 3000 }),
                                cx,
                            );
                        }
                    })
            })
            .child(notification_host()) // Must be last to render on top
    }
}

Clone this wiki locally