TypeScript/JavaScript API bindings for Tauri applications providing comprehensive desktop app functionality
—
Real-time bidirectional communication system between frontend and backend with support for custom events, built-in system events, and flexible targeting options.
Listen for events from the backend or other parts of the application.
/**
* Listen for an event and call handler each time it occurs
* @param event - Event name to listen for
* @param handler - Function to call when event occurs
* @param options - Optional targeting and configuration
* @returns Promise resolving to function that removes the listener
*/
function listen<T>(
event: EventName,
handler: EventCallback<T>,
options?: Options
): Promise<UnlistenFn>;
/**
* Listen for an event and call handler only once
* @param event - Event name to listen for
* @param handler - Function to call when event occurs
* @param options - Optional targeting and configuration
* @returns Promise resolving to function that removes the listener
*/
function once<T>(
event: EventName,
handler: EventCallback<T>,
options?: Options
): Promise<UnlistenFn>;
type EventCallback<T> = (event: Event<T>) => void;
type UnlistenFn = () => void;
type EventName = string;
interface Options {
target?: EventTarget;
}Send events to other parts of the application or the backend.
/**
* Emit an event to all listeners
* @param event - Event name to emit
* @param payload - Optional data to send with event
*/
function emit<T>(event: string, payload?: T): Promise<void>;
/**
* Emit an event to a specific target
* @param target - Target to send event to
* @param event - Event name to emit
* @param payload - Optional data to send with event
*/
function emitTo<T>(
target: EventTarget | string,
event: string,
payload?: T
): Promise<void>;Structure of events received by handlers.
/**
* Event object passed to event handlers
*/
interface Event<T> {
/** Event name */
event: string;
/** Unique event ID */
id: number;
/** Event payload data */
payload: T;
}Control which components receive events.
/**
* Event targeting options
*/
type EventTarget =
| { Any: null }
| { AnyLabel: { label: string } }
| { App: null }
| { Window: { label: string } }
| { Webview: { label: string } }
| { WebviewWindow: { label: string } };Predefined events automatically emitted by Tauri for system state changes.
/**
* Built-in Tauri events
*/
enum TauriEvent {
// Window events
WINDOW_RESIZED = 'tauri://resize',
WINDOW_MOVED = 'tauri://move',
WINDOW_CLOSE_REQUESTED = 'tauri://close-requested',
WINDOW_DESTROYED = 'tauri://destroyed',
WINDOW_FOCUS = 'tauri://focus',
WINDOW_BLUR = 'tauri://blur',
WINDOW_SCALE_FACTOR_CHANGED = 'tauri://scale-change',
WINDOW_THEME_CHANGED = 'tauri://theme-changed',
WINDOW_FILE_DROP = 'tauri://file-drop',
WINDOW_FILE_DROP_HOVER = 'tauri://file-drop-hover',
WINDOW_FILE_DROP_CANCELLED = 'tauri://file-drop-cancelled',
// Webview events
WEBVIEW_CREATED = 'tauri://webview-created',
// Menu events
MENU = 'tauri://menu',
// Tray events
TRAY_CLICK = 'tauri://tray-click',
TRAY_DOUBLE_CLICK = 'tauri://tray-double-click',
TRAY_RIGHT_CLICK = 'tauri://tray-right-click',
TRAY_ENTER = 'tauri://tray-enter',
TRAY_LEAVE = 'tauri://tray-leave',
TRAY_MOVE = 'tauri://tray-move'
}Events for handling file drag-and-drop operations.
/**
* File drop event types
*/
type DragDropEvent =
| { type: 'drop'; paths: string[]; position: PhysicalPosition }
| { type: 'hover'; paths: string[]; position: PhysicalPosition }
| { type: 'cancel' };import { listen, once } from '@tauri-apps/api/event';
// Listen for custom events from backend
const unlisten = await listen<string>('backend-message', (event) => {
console.log('Received message:', event.payload);
console.log('Event ID:', event.id);
});
// Listen for event only once
await once<{ status: string }>('initialization-complete', (event) => {
console.log('App initialized with status:', event.payload.status);
});
// Remove listener when done
unlisten();import { listen, TauriEvent } from '@tauri-apps/api/event';
// Handle window resize
await listen(TauriEvent.WINDOW_RESIZED, (event) => {
const { width, height } = event.payload;
console.log(`Window resized to ${width}x${height}`);
// Adjust UI layout
});
// Handle window focus/blur
await listen(TauriEvent.WINDOW_FOCUS, () => {
document.body.classList.add('focused');
});
await listen(TauriEvent.WINDOW_BLUR, () => {
document.body.classList.remove('focused');
});
// Handle theme changes
await listen(TauriEvent.WINDOW_THEME_CHANGED, (event) => {
const theme = event.payload.theme; // 'light' | 'dark'
document.documentElement.setAttribute('data-theme', theme);
});import { listen, TauriEvent } from '@tauri-apps/api/event';
// Handle file drops
await listen<DragDropEvent>(TauriEvent.WINDOW_FILE_DROP, (event) => {
if (event.payload.type === 'drop') {
const files = event.payload.paths;
console.log('Files dropped:', files);
processDroppedFiles(files);
}
});
// Handle drag hover
await listen<DragDropEvent>(TauriEvent.WINDOW_FILE_DROP_HOVER, (event) => {
if (event.payload.type === 'hover') {
document.body.classList.add('drag-over');
showDropZone();
}
});
// Handle drag cancel
await listen<DragDropEvent>(TauriEvent.WINDOW_FILE_DROP_CANCELLED, () => {
document.body.classList.remove('drag-over');
hideDropZone();
});
function processDroppedFiles(files: string[]) {
files.forEach(async (file) => {
if (file.endsWith('.json')) {
// Process JSON files
const content = await readTextFile(file);
console.log('JSON content:', JSON.parse(content));
} else if (file.match(/\.(jpg|png|gif)$/i)) {
// Process image files
const image = await Image.fromPath(file);
displayImage(image);
}
});
}import { emit, emitTo, listen } from '@tauri-apps/api/event';
// Frontend to backend communication
await emit('user-action', {
type: 'button-click',
buttonId: 'save-btn'
});
// Send data to backend for processing
await emit('process-data', {
data: [1, 2, 3, 4, 5],
algorithm: 'quicksort'
});
// Listen for backend responses
await listen<{ result: number[] }>('data-processed', (event) => {
console.log('Processed data:', event.payload.result);
});
// Inter-window communication
await emitTo('settings-window', 'config-updated', {
theme: 'dark',
language: 'en'
});import { emitTo } from '@tauri-apps/api/event';
// Send to specific window
await emitTo(
{ Window: { label: 'main-window' } },
'refresh-data',
{ timestamp: Date.now() }
);
// Send to specific webview
await emitTo(
{ Webview: { label: 'content-view' } },
'scroll-to-top',
null
);
// Send to all windows with specific label pattern
await emitTo(
{ AnyLabel: { label: 'editor-*' } },
'save-all',
{ force: true }
);
// Send to entire application
await emitTo(
{ App: null },
'global-setting-changed',
{ setting: 'theme', value: 'dark' }
);import { listen, emit } from '@tauri-apps/api/event';
class EventBus {
private listeners = new Map<string, Function[]>();
async subscribe<T>(event: string, callback: (payload: T) => void) {
const unlistenFn = await listen<T>(event, (e) => callback(e.payload));
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event)!.push(unlistenFn);
return unlistenFn;
}
async publish<T>(event: string, payload: T) {
await emit(event, payload);
}
cleanup() {
this.listeners.forEach(unlisteners => {
unlisteners.forEach(unlisten => unlisten());
});
this.listeners.clear();
}
}
// Usage
const eventBus = new EventBus();
// Subscribe to events
await eventBus.subscribe<string>('user-login', (username) => {
console.log(`User ${username} logged in`);
updateUI();
});
await eventBus.subscribe<{ error: string }>('api-error', (data) => {
showErrorNotification(data.error);
});
// Publish events
await eventBus.publish('user-login', 'john_doe');
await eventBus.publish('api-error', { error: 'Network timeout' });import { listen } from '@tauri-apps/api/event';
// Handle menu item clicks
await listen<{ menuItemId: string }>('tauri://menu', (event) => {
const menuId = event.payload.menuItemId;
switch (menuId) {
case 'file-new':
createNewFile();
break;
case 'file-open':
openFileDialog();
break;
case 'edit-copy':
copyToClipboard();
break;
case 'view-toggle-sidebar':
toggleSidebar();
break;
default:
console.log('Unknown menu item:', menuId);
}
});import { listen } from '@tauri-apps/api/event';
// Handle tray icon interactions
await listen('tauri://tray-click', (event) => {
console.log('Tray clicked:', event.payload);
toggleMainWindow();
});
await listen('tauri://tray-double-click', () => {
showMainWindow();
});
await listen('tauri://tray-right-click', () => {
// Context menu automatically shown
console.log('Tray right-clicked');
});import { listen } from '@tauri-apps/api/event';
class ComponentWithEvents {
private unlisteners: (() => void)[] = [];
async initialize() {
// Register multiple event listeners
const unlisten1 = await listen('event1', this.handleEvent1.bind(this));
const unlisten2 = await listen('event2', this.handleEvent2.bind(this));
const unlisten3 = await listen('event3', this.handleEvent3.bind(this));
this.unlisteners.push(unlisten1, unlisten2, unlisten3);
}
private handleEvent1(event: Event<any>) {
try {
// Handle event
} catch (error) {
console.error('Error handling event1:', error);
}
}
private handleEvent2(event: Event<any>) {
// Handle event
}
private handleEvent3(event: Event<any>) {
// Handle event
}
cleanup() {
// Remove all listeners when component is destroyed
this.unlisteners.forEach(unlisten => unlisten());
this.unlisteners = [];
}
}
// Usage
const component = new ComponentWithEvents();
await component.initialize();
// Later, when component is no longer needed
component.cleanup();import { listen, emit } from '@tauri-apps/api/event';
// Debounce high-frequency events
function debounce<T extends (...args: any[]) => void>(
func: T,
wait: number
): T {
let timeout: NodeJS.Timeout;
return ((...args: any[]) => {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
}) as T;
}
// Handle resize events efficiently
const debouncedResize = debounce((size: { width: number; height: number }) => {
console.log('Window resized to:', size);
// Expensive layout recalculation
}, 250);
await listen(TauriEvent.WINDOW_RESIZED, (event) => {
debouncedResize(event.payload);
});
// Batch multiple events
let eventQueue: any[] = [];
const processQueue = () => {
if (eventQueue.length > 0) {
console.log('Processing', eventQueue.length, 'events');
// Process all queued events at once
eventQueue = [];
}
};
await listen('high-frequency-event', (event) => {
eventQueue.push(event.payload);
});
// Process queue periodically
setInterval(processQueue, 100);Install with Tessl CLI
npx tessl i tessl/npm-tauri-apps--api