Creating an app in tauri with a system tray and svelte frontend window - Stack Overflow

admin2025-04-28  2

Im trying out tauri (v2) for the first time (love it), but the documentation is lacking. Im creating a frontend in svelte, and I dont want the window to close, but rather run in the background as a system tray application, and upon double clicking, it should reopen the webview window. Following the documentation, this is my tray.ts file

import { defaultWindowIcon } from "@tauri-apps/api/app";
import { TrayIcon, type TrayIconOptions } from "@tauri-apps/api/tray";
import { Menu } from "@tauri-apps/api/menu";
import { getCurrentWindow,Window } from "@tauri-apps/api/window";
import { Webview } from "@tauri-apps/api/webview";

function onTrayMenuClick(itemId: string) {}

const menu = await Menu.new({
  items: [
    {
      id: "quit",
      text: "Quit",
      action: onTrayMenuClick,
    },
  ],
});

const options: TrayIconOptions = {
  icon: (await defaultWindowIcon()) ?? "default-icon.png",
  menu,
  action: (event) => {
    switch (event.type) {
      case "DoubleClick":
        console.log(`mouse ${event.button} button pressed`);
        break;
    }
  },
  showMenuOnLeftClick: true,
  tooltip: "Tauri App",
};

export const tray = await TrayIcon.new(options);

The svelte code is normal svelte code, not interfering with any native features except maybe the ability to send notifications.

<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import { sendNotification } from '@tauri-apps/plugin-notification';
  import { fetch } from '@tauri-apps/plugin-http';

 
  async function requestNotificationPermission() {
    try {
      await Notification.requestPermission();
    } catch (error) {
      console.error('Error requesting notification permission:', error);
    }
  }
// and so on

The problem im encountering is that i dont know how to implement the non-closure of the window when X is clicked, and how to make the tray app's quit functionality make the app stop instead (hence the code is blank)

Im trying out tauri (v2) for the first time (love it), but the documentation is lacking. Im creating a frontend in svelte, and I dont want the window to close, but rather run in the background as a system tray application, and upon double clicking, it should reopen the webview window. Following the documentation, this is my tray.ts file

import { defaultWindowIcon } from "@tauri-apps/api/app";
import { TrayIcon, type TrayIconOptions } from "@tauri-apps/api/tray";
import { Menu } from "@tauri-apps/api/menu";
import { getCurrentWindow,Window } from "@tauri-apps/api/window";
import { Webview } from "@tauri-apps/api/webview";

function onTrayMenuClick(itemId: string) {}

const menu = await Menu.new({
  items: [
    {
      id: "quit",
      text: "Quit",
      action: onTrayMenuClick,
    },
  ],
});

const options: TrayIconOptions = {
  icon: (await defaultWindowIcon()) ?? "default-icon.png",
  menu,
  action: (event) => {
    switch (event.type) {
      case "DoubleClick":
        console.log(`mouse ${event.button} button pressed`);
        break;
    }
  },
  showMenuOnLeftClick: true,
  tooltip: "Tauri App",
};

export const tray = await TrayIcon.new(options);

The svelte code is normal svelte code, not interfering with any native features except maybe the ability to send notifications.

<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import { sendNotification } from '@tauri-apps/plugin-notification';
  import { fetch } from '@tauri-apps/plugin-http';

 
  async function requestNotificationPermission() {
    try {
      await Notification.requestPermission();
    } catch (error) {
      console.error('Error requesting notification permission:', error);
    }
  }
// and so on

The problem im encountering is that i dont know how to implement the non-closure of the window when X is clicked, and how to make the tray app's quit functionality make the app stop instead (hence the code is blank)

Share Improve this question asked Jan 9 at 18:19 Haider MuhammadHaider Muhammad 311 silver badge5 bronze badges 1
  • I tried adding an import for the tray function and called it in the onMount function, but that didnt even render the tray icon – Haider Muhammad Commented Jan 9 at 18:20
Add a comment  | 

1 Answer 1

Reset to default 1

The problem im encountering is that i dont know how to implement the non-closure of the window when X is clicked

I had the same problem last year. I implemented it by handling the WindowEvent::CloseRequested event. So, basically, I hide a window instead of closing it. Here is my code: https://github.com/TheBestTvarynka/Dataans/blob/66038e3aed3b7abd80f71dc5bd23bfd1cb7d4c74/dataans/src-tauri/src/main.rs#L185-L190

        .on_window_event(|window, event| {
            if let tauri::WindowEvent::CloseRequested { api, .. } = event {
                window.hide().unwrap();
                api.prevent_close();
            }
        })

I did it on the Rust-side (on the backend), but you can try to find similar methods and do the same on the frontend.

and how to make the tray app's quit functionality make the app stop instead

You can implement it by adding the on_menu_event handler for your tray menu. You can use my code as a reference: https://github.com/TheBestTvarynka/Dataans/blob/66038e3aed3b7abd80f71dc5bd23bfd1cb7d4c74/dataans/src-tauri/src/main.rs#L109-L130

            // Set up system tray
            let toggle_visibility =
                MenuItemBuilder::with_id(WINDOW_VISIBILITY_MENU_ITEM_ID, WINDOW_VISIBILITY_TITLE).build(app)?;
            let quit = MenuItemBuilder::with_id(WINDOW_QUIT_MENU_ITEM_ID, WINDOW_QUIT_TITLE).build(app)?;

            let menu = MenuBuilder::new(app).items(&[&toggle_visibility, &quit]).build()?;

            if let Some(tray_icon) = app.tray_by_id("main") {
                tray_icon.set_menu(Some(menu)).unwrap();
                tray_icon.on_menu_event(move |app, event| match event.id().as_ref() {
                    WINDOW_VISIBILITY_MENU_ITEM_ID => toggle_app_visibility(app).unwrap(),
                    WINDOW_QUIT_MENU_ITEM_ID => {
                        info!("Exiting the app...");

                        app.cleanup_before_exit();
                        std::process::exit(0);
                    }
                    event_id => warn!(?event_id, "Unknown tray event id"),
                });
            } else {
                warn!("Cannot find the 'main' try icon :(");
            }

Again, I did it on the backend, but you can configure it on the frontend side.

Feel free to ask any additional questions :)

转载请注明原文地址:http://anycun.com/QandA/1745781166a91205.html