A lightweight, unified Python library for creating system tray/menu bar icons across Windows, macOS, and Linux. No heavy GUI dependencies—just pure Python simplicity for status indicators, notifications, and menus.
- Cross-Platform Magic: Handles OS-specific quirks automatically (e.g., Windows notification area, macOS menu bar, Linux systray).
- Minimal Footprint: Dependency-free core (uses stdlib where possible, optional extras for icons/notifications).
- Easy API: Object-oriented and chainable, inspired by
pathlibfor intuitive use. - Async-Friendly: Supports asyncio for real-time updates without blocking.
Perfect for building desktop utilities like monitors, trackers, or background apps.
pip install crosstrayfrom crosstray import Tray
tray = Tray(icon="path/to/icon.png", title="My App")
tray.add_menu_item("Quit", lambda: tray.quit())
tray.run()For more examples, see Usage.
- Create tray icons with custom images or text fallbacks.
- Build nested menus with callbacks.
- Show balloon notifications/toasts.
- Dynamic updates (e.g., change icon or menu on the fly).
- Event loop integration for async apps.
- Error handling for unsupported platforms.
from crosstray import Tray
def on_click(tray: ct.Tray):
tray.send_notification("Tray Clicked", "You clicked the tray icon!", icon="file.ico", timeout=9000)
tray = Tray(icon="icon.ico", tooltip="Hello World")
tray.on_click = tray.on_click = lambda: on_click(tray) # Or use tray.add_action("Click", on_click)
tray.run() # Blocks until quitfrom crosstray import Tray, MenuItem
tray = Tray(title="Status Monitor")
menu = tray.menu
menu.add_item(MenuItem("Refresh", lambda: print("Refreshing...")))
menu.add_separator()
submenu = menu.add_submenu("Settings")
submenu.add_item(MenuItem("Option 1", lambda: print("Selected 1")))
menu.add_item(MenuItem("Quit", tray.quit))
tray.run()import asyncio
from crosstray import Tray
async def main():
tray = Tray(icon="icon.png")
tray.add_menu_item("Update", lambda: print("Updating"))
# Simulate real-time update
async def updater():
while True:
tray.tooltip = f"Time: {asyncio.get_event_loop().time()}"
await asyncio.sleep(1)
asyncio.create_task(updater())
await tray.run_async() # Non-blocking
asyncio.run(main())Contributions welcome! Fork the repo, create a branch, and submit a PR. See CONTRIBUTING.md for guidelines.
MIT License. See LICENSE for details.
Built with ❤️ by Uman Sheikh. Inspired by community needs for simpler desktop tools.