Features

Dynamic Island

A running live activity shows in the Dynamic Island: on an iPhone the system island, on desktop a pill the plugin draws at the top centre of the screen — around the camera notch on a notched Mac. The same request drives both, with the same regions.

Desktop island: compact pill, expanded on hover, collapsed again (built-in renderer).

Start one

import { startActivity, updateActivity, endActivity } from "tauri-plugin-widgets-api";

await startActivity({
  id: "timer",
  title: "Focus",
  icon: "timer",
  endsAt: Date.now() + 25 * 60_000,          // compact trailing shows the countdown
  compactLeading: { type: "image", systemName: "brain.head.profile", color: "#a78bfa" },
  compactTrailing: { type: "timer", targetDate: new Date(Date.now() + 25 * 60_000).toISOString(), counting: "down" },
  islandCenter: { type: "text", content: "Deep work", fontWeight: "semibold" },
  layout: { type: "progress", value: 0.1, tint: "#a78bfa" },
  keylineTint: "#a78bfa",
});

await updateActivity({ id: "timer", layout: { type: "progress", value: 0.6, tint: "#a78bfa" } });
await endActivity("timer", 3_000);

Without the region fields the plugin fills them from title, icon, progress and endsAt, so a plain startActivity already gets a sensible pill.

Regions

StateShowsiPhoneDesktop
CompactcompactLeading and compactTrailing either side of the camera (default: icon, and the endsAt countdown or progress %)yesyes
Minimalother running activities as small circles (minimal, default icon); a click brings one to the pillyesyes
ExpandedislandLeading / islandTrailing in the top band, islandCenter under it, layout at the bottomlong presshover or click
Lock ScreenlockScreen (else layout)yes—

keylineTint outlines the pill. Every region is an ordinary widget element: text, timers, progress, images, stacks, buttons.

Different activities in the same pill: progress, a countdown, a live chart, an animated face.

Taps and a launcher

Elements with action or url work in every region. Taps arrive like widget taps, with widgetId: "activity.<id>":

import { onWidgetAction, createWidgetWindow } from "tauri-plugin-widgets-api";

await onWidgetAction(async ({ widgetId, action }) => {
  if (widgetId === "activity.timer" && action === "open") {
    // Open a small window under the island, like a launcher.
    await createWidgetWindow({ label: "launcher", widgetId: "launcher", size: "medium", y: 48 });
  }
});
A click on the island opens a launcher window with app icons.

Desktop placement

plugins.widgets.activitySurface picks the desktop surface: "island" (default), "window" (the older corner window) or "notification" (Linux / Windows, feature notify). The island is one borderless window per app.

PlatformPlacement and window
Mac with a notch (Apple silicon)pill as tall as the notch, wrapping it (NSScreen.safeAreaInsets, auxiliaryTopLeftArea / auxiliaryTopRightArea); window level above the menu bar, on every Space and over full-screen apps
Mac without a notchfloating pill just under the menu bar
Windowstop-centre topmost tool window, no taskbar button, does not take focus
Linux X11top-centre DOCK window above other windows
Linux Waylandwith feature layer-shell: an Overlay layer surface anchored to the top edge; without it an ordinary always-on-top window wherever the compositor puts it

The window is always exactly the visible shapes, so clicks next to the pill reach the windows below. Hover is read from the global cursor position (a webview in an inactive macOS app gets no mouse-enter events); where that is unavailable (Wayland), the page's own hover and a click expand it, and a click on the top band collapses it.

Setup

  • Desktop. Allow the island window label in your capability ("windows": ["main", "activity-*"]). On macOS enable the plugin feature macos-private-api and app.macOSPrivateApi: true for the transparent, rounded pill.
  • iOS. Add TauriLiveActivity() to the extension's WidgetBundle and NSSupportsLiveActivities = YES to the app's Info.plist (init-ios does both); see Live activities.

The whole request stays under 4 KiB of JSON (the ActivityKit limit), checked on every platform.