wails/website/docs/reference/runtime/notification.mdx
Zach Botterman 51d30325fc
[v2] Notifications API (#4256)
* init v2

* implement macOS and Windows

* minor cleanup

* fix segfault

* linux

* 🐰

* remove windows init

* formatting

* fix win icon

* clean

* clean

* codesign full path

* fix en/decoding and notification types

* changelog & docs

* fix options and channel fix

* update docs

* correct docs

* Update website/docs/reference/runtime/notification.mdx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* work through rabbit suggestions

* nil checks, cleanups, docs

* locks

* Update v2/internal/frontend/desktop/windows/notifications.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* update js runtime

* update docs

* second pass of comments

* coherent JSON key, icon improv

---------

Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-15 02:38:32 +00:00

601 lines
18 KiB
Text

---
sidebar_position: 6
---
# Notification
This part of the runtime provides access to native system notifications with support for interactive elements like action buttons and text input fields.
### InitializeNotifications
Initializes the notification system. It should be called during app startup.
**Go:** `InitializeNotifications(ctx context.Context) error`
**JavaScript:** `InitializeNotifications(): Promise<void>`
Returns: Error if initialization fails
**Example:**
```go
err := runtime.InitializeNotifications(ctx)
if err != nil {
log.Fatal(err)
}
```
```javascript
await runtime.InitializeNotifications();
```
### IsNotificationAvailable
Checks if notifications are supported on the current platform.
**Go:** `IsNotificationAvailable(ctx context.Context) bool`
**JavaScript:** `IsNotificationAvailable(): Promise<boolean>`
Returns: `true` if notifications are supported, `false` otherwise
**Example:**
```go
if !runtime.IsNotificationAvailable(ctx) {
log.Println("Notifications not available on this platform")
}
```
```javascript
const available = await runtime.IsNotificationAvailable();
if (!available) {
console.log("Notifications not available on this platform");
}
```
### RequestNotificationAuthorization
Requests permission to display notifications (macOS only). On Windows and Linux, this always returns `true`.
**Go:** `RequestNotificationAuthorization(ctx context.Context) (bool, error)`
**JavaScript:** `RequestNotificationAuthorization(): Promise<boolean>`
Returns: Authorization status and error
**Example:**
```go
authorized, err := runtime.RequestNotificationAuthorization(ctx)
```
```javascript
const authorized = await runtime.RequestNotificationAuthorization();
```
### CheckNotificationAuthorization
Checks the current notification authorization status (macOS only). On Windows and Linux, this always returns `true`.
**Go:** `CheckNotificationAuthorization(ctx context.Context) (bool, error)`
**JavaScript:** `CheckNotificationAuthorization(): Promise<boolean>`
Returns: Authorization status and error
**Example:**
```go
authorized, err := runtime.CheckNotificationAuthorization(ctx)
```
```javascript
const authorized = await runtime.CheckNotificationAuthorization();
```
### CleanupNotifications
Cleans up notification resources and releases any held connections. This should be called when shutting down the application, particularly on Linux where it closes the D-Bus connection.
**Go:** `CleanupNotifications(ctx context.Context)`
**JavaScript:** `CleanupNotifications(): Promise<void>`
**Example:**
```go
runtime.CleanupNotifications(ctx)
```
```javascript
await runtime.CleanupNotifications();
```
### SendNotification
Sends a basic notification to the system.
**Go:** `SendNotification(ctx context.Context, options NotificationOptions) error`
**JavaScript:** `SendNotification(options: NotificationOptions): Promise<void>`
Returns: Error if the notification fails to send
**Example:**
```go
err := runtime.SendNotification(ctx, runtime.NotificationOptions{
ID: "notif-1",
Title: "Hello",
Body: "This is a notification",
})
```
```javascript
await runtime.SendNotification({
id: "notif-1",
title: "Hello",
body: "This is a notification"
});
```
### SendNotificationWithActions
Sends an interactive notification with predefined actions. Requires a registered notification category. If the category is not found or `CategoryID` is empty, a basic notification will be sent instead.
**Go:** `SendNotificationWithActions(ctx context.Context, options NotificationOptions) error`
**JavaScript:** `SendNotificationWithActions(options: NotificationOptions): Promise<void>`
Returns: Error if the notification fails to send
**Example:**
```go
err := runtime.SendNotificationWithActions(ctx, runtime.NotificationOptions{
ID: "notif-2",
Title: "Task Reminder",
Body: "Complete your task",
CategoryID: "TASK_CATEGORY",
})
```
```javascript
await runtime.SendNotificationWithActions({
id: "notif-2",
title: "Task Reminder",
body: "Complete your task",
categoryId: "TASK_CATEGORY"
});
```
### RegisterNotificationCategory
Registers a notification category that can be used with interactive notifications. Registering a category with the same ID as a previously registered category will override it.
**Go:** `RegisterNotificationCategory(ctx context.Context, category NotificationCategory) error`
**JavaScript:** `RegisterNotificationCategory(category: NotificationCategory): Promise<void>`
Returns: Error if registration fails
**Example:**
```go
err := runtime.RegisterNotificationCategory(ctx, runtime.NotificationCategory{
ID: "TASK_CATEGORY",
Actions: []runtime.NotificationAction{
{ID: "COMPLETE", Title: "Complete"},
{ID: "CANCEL", Title: "Cancel"},
},
})
```
```javascript
await runtime.RegisterNotificationCategory({
id: "TASK_CATEGORY",
actions: [
{id: "COMPLETE", title: "Complete"},
{id: "CANCEL", title: "Cancel"}
]
});
```
### RemoveNotificationCategory
Removes a previously registered notification category.
**Go:** `RemoveNotificationCategory(ctx context.Context, categoryId string) error`
**JavaScript:** `RemoveNotificationCategory(categoryId: string): Promise<void>`
Returns: Error if removal fails
**Example:**
```go
err := runtime.RemoveNotificationCategory(ctx, "TASK_CATEGORY")
```
```javascript
await runtime.RemoveNotificationCategory("TASK_CATEGORY");
```
### RemoveAllPendingNotifications
Removes all pending notifications (macOS and Linux only).
**Go:** `RemoveAllPendingNotifications(ctx context.Context) error`
**JavaScript:** `RemoveAllPendingNotifications(): Promise<void>`
Returns: Error if removal fails
**Example:**
```go
err := runtime.RemoveAllPendingNotifications(ctx)
```
```javascript
await runtime.RemoveAllPendingNotifications();
```
### RemovePendingNotification
Removes a specific pending notification (macOS and Linux only).
**Go:** `RemovePendingNotification(ctx context.Context, identifier string) error`
**JavaScript:** `RemovePendingNotification(identifier: string): Promise<void>`
Returns: Error if removal fails
**Example:**
```go
err := runtime.RemovePendingNotification(ctx, "notif-1")
```
```javascript
await runtime.RemovePendingNotification("notif-1");
```
### RemoveAllDeliveredNotifications
Removes all delivered notifications (macOS and Linux only).
**Go:** `RemoveAllDeliveredNotifications(ctx context.Context) error`
**JavaScript:** `RemoveAllDeliveredNotifications(): Promise<void>`
Returns: Error if removal fails
**Example:**
```go
err := runtime.RemoveAllDeliveredNotifications(ctx)
```
```javascript
await runtime.RemoveAllDeliveredNotifications();
```
### RemoveDeliveredNotification
Removes a specific delivered notification (macOS and Linux only).
**Go:** `RemoveDeliveredNotification(ctx context.Context, identifier string) error`
**JavaScript:** `RemoveDeliveredNotification(identifier: string): Promise<void>`
Returns: Error if removal fails
**Example:**
```go
err := runtime.RemoveDeliveredNotification(ctx, "notif-1")
```
```javascript
await runtime.RemoveDeliveredNotification("notif-1");
```
### RemoveNotification
Removes a notification by identifier (Linux only). On macOS and Windows, this is a stub that always returns `nil`.
**Go:** `RemoveNotification(ctx context.Context, identifier string) error`
**JavaScript:** `RemoveNotification(identifier: string): Promise<void>`
Returns: Error if removal fails
**Example:**
```go
err := runtime.RemoveNotification(ctx, "notif-1")
```
```javascript
await runtime.RemoveNotification("notif-1");
```
### OnNotificationResponse
Registers a callback function to handle notification responses when users interact with notifications.
**Go:** `OnNotificationResponse(ctx context.Context, callback func(result NotificationResult))`
:::note JavaScript
`OnNotificationResponse` is not available in the JavaScript runtime. Instead, JavaScript applications should use the [Events API](/docs/reference/runtime/events) to listen for notification responses. From your Go callback, emit an event that your JavaScript code can listen to.
**Example:**
```go
runtime.OnNotificationResponse(ctx, func(result runtime.NotificationResult) {
if result.Error != nil {
return
}
// Emit an event that JavaScript can listen to
runtime.EventsEmit(ctx, "notification-response", result.Response)
})
```
```javascript
runtime.EventsOn("notification-response", (response) => {
console.log("Notification response:", response);
switch (response.actionIdentifier) {
case "COMPLETE":
// Handle complete action
break;
case "CANCEL":
// Handle cancel action
break;
}
});
```
:::
## Options
### NotificationOptions
**Go:**
```go
type NotificationOptions struct {
ID string `json:"id"`
Title string `json:"title"`
Subtitle string `json:"subtitle,omitempty"` // (macOS and Linux only)
Body string `json:"body,omitempty"`
CategoryID string `json:"categoryId,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
}
```
**TypeScript:**
```typescript
interface NotificationOptions {
id: string;
title: string;
subtitle?: string; // macOS and Linux only
body?: string;
categoryId?: string;
data?: { [key: string]: any };
}
```
| Field | Description | Win | Mac | Lin |
|-------------|------------------------------------------------|-----|-----|-----|
| ID | Unique identifier for the notification | ✅ | ✅ | ✅ |
| Title | Main notification title | ✅ | ✅ | ✅ |
| Subtitle | Subtitle text (macOS and Linux only) | | ✅ | ✅ |
| Body | Main notification content | ✅ | ✅ | ✅ |
| CategoryID | Category identifier for interactive notifications | ✅ | ✅ | ✅ |
| Data | Custom data to associate with the notification | ✅ | ✅ | ✅ |
### NotificationCategory
**Go:**
```go
type NotificationCategory struct {
ID string `json:"id,omitempty"`
Actions []NotificationAction `json:"actions,omitempty"`
HasReplyField bool `json:"hasReplyField,omitempty"`
ReplyPlaceholder string `json:"replyPlaceholder,omitempty"`
ReplyButtonTitle string `json:"replyButtonTitle,omitempty"`
}
```
**TypeScript:**
```typescript
interface NotificationCategory {
id?: string;
actions?: NotificationAction[];
hasReplyField?: boolean;
replyPlaceholder?: string;
replyButtonTitle?: string;
}
```
| Field | Description | Win | Mac | Lin |
|------------------|------------------------------------------------|-----|-----|-----|
| ID | Unique identifier for the category | ✅ | ✅ | ✅ |
| Actions | Array of action buttons | ✅ | ✅ | ✅ |
| HasReplyField | Whether to include a text input field | ✅ | ✅ | |
| ReplyPlaceholder | Placeholder text for the input field | ✅ | ✅ | |
| ReplyButtonTitle | Text for the reply button | ✅ | ✅ | |
### NotificationAction
**Go:**
```go
type NotificationAction struct {
ID string `json:"id,omitempty"`
Title string `json:"title,omitempty"`
Destructive bool `json:"destructive,omitempty"` // (macOS-specific)
}
```
**TypeScript:**
```typescript
interface NotificationAction {
id?: string;
title?: string;
destructive?: boolean; // macOS-specific
}
```
| Field | Description | Win | Mac | Lin |
|-------------|------------------------------------------------|----------------|-----|-----|
| ID | Unique identifier for the action | ✅ | ✅ | ✅ |
| Title | Button text | ✅ | ✅ | ✅ |
| Destructive | Whether the action is destructive (macOS-only) | | ✅ | |
#### macOS-specific Behavior
On macOS, the `Destructive` flag causes the action button to appear in red, indicating it's a destructive action (like delete or cancel). On Windows and Linux, this flag is ignored.
Example:
```go
actions := []runtime.NotificationAction{
{ID: "SAVE", Title: "Save"},
{ID: "DELETE", Title: "Delete", Destructive: true}, // Shows as red button on macOS
}
```
### NotificationResponse
```go
type NotificationResponse struct {
ID string `json:"id,omitempty"`
ActionIdentifier string `json:"actionIdentifier,omitempty"`
CategoryID string `json:"categoryId,omitempty"` // Consistent with NotificationOptions
Title string `json:"title,omitempty"`
Subtitle string `json:"subtitle,omitempty"` // (macOS and Linux only)
Body string `json:"body,omitempty"`
UserText string `json:"userText,omitempty"`
UserInfo map[string]interface{} `json:"userInfo,omitempty"`
}
```
| Field | Description | Win | Mac | Lin |
|------------------|------------------------------------------------|-----|-----|-----|
| ID | Notification identifier | ✅ | ✅ | ✅ |
| ActionIdentifier | Action that was triggered | ✅ | ✅ | ✅ |
| CategoryID | Category of the notification | ✅ | ✅ | ✅ |
| Title | Title of the notification | ✅ | ✅ | ✅ |
| Subtitle | Subtitle of the notification (macOS and Linux only) | | ✅ | ✅ |
| Body | Body text of the notification | ✅ | ✅ | ✅ |
| UserText | Text entered by the user | ✅ | ✅ | |
| UserInfo | Custom data from the notification | ✅ | ✅ | ✅ |
### NotificationResult
```go
type NotificationResult struct {
Response NotificationResponse
Error error
}
```
| Field | Description |
|----------|------------------------------------------------|
| Response | The notification response data |
| Error | Any error that occurred during the interaction |
## Platform-Specific Behavior
### macOS
- **Authorization Required**: Apps must request notification permission before sending notifications
- **Notarization**: Apps must be notarized for distribution
- **Features**: All features supported including subtitles, text input, and destructive actions
- **Styling**: Automatically adapts to system dark/light mode
- **Center**: Notifications appear in macOS Notification Center
**Example:**
```go
// Check and request authorization
authorized, err := runtime.CheckNotificationAuthorization(ctx)
if err != nil {
return err
}
if !authorized {
authorized, err = runtime.RequestNotificationAuthorization(ctx)
if err != nil || !authorized {
return fmt.Errorf("notification authorization denied")
}
}
// Now send notifications
```
```javascript
// Check and request authorization
let authorized = await runtime.CheckNotificationAuthorization();
if (!authorized) {
authorized = await runtime.RequestNotificationAuthorization();
if (!authorized) {
throw new Error("Notification authorization denied");
}
}
// Now send notifications
```
### Windows
- **No Authorization**: Permission system not required
- **Features**: Supports text input and high DPI displays
- **Limitations**: Subtitle not supported
- **Styling**: Adapts to Windows theme settings
- **Behavior**: Uses Windows toast notification system
### Linux
- **Desktop Environment Dependent**: Behavior varies by DE (GNOME, KDE, XFCE, etc.)
- **Features**: Supports subtitles
- **Limitations**: User text input not supported
- **Styling**: Follows desktop environment theme
- **Behavior**: Uses native notification system when available
**Example:**
```go
// Check system support
if !runtime.IsNotificationAvailable(ctx) {
return fmt.Errorf("notifications not supported on this Linux desktop")
}
// Linux notifications may not support text input
// Only use actions that don't require user text
```
```javascript
// Check system support
const available = await runtime.IsNotificationAvailable();
if (!available) {
throw new Error("Notifications not supported on this Linux desktop");
}
// Linux notifications may not support text input
// Only use actions that don't require user text
```
## Action Identifiers
When handling notification responses, these special action identifiers may be present:
- `DEFAULT_ACTION`: Triggered when the user clicks the notification itself (not an action button)
- `TEXT_REPLY`: Triggered when the user submits text via the reply field
Example response handling:
```go
runtime.OnNotificationResponse(ctx, func(result runtime.NotificationResult) {
if result.Error != nil {
fmt.Printf("Response error: %v\n", result.Error)
return
}
response := result.Response
switch response.ActionIdentifier {
case "DEFAULT_ACTION":
fmt.Println("User clicked the notification")
case "TEXT_REPLY":
fmt.Printf("User replied: %s\n", response.UserText)
case "COMPLETE":
fmt.Println("User clicked Complete button")
case "CANCEL":
fmt.Println("User clicked Cancel button")
}
})
```