Bridge Components - aguspe/turbo_desktop GitHub Wiki
Bridge Components
Bridge Components are the desktop equivalent of Strada — they let your web UI talk to native OS features through structured message passing.
How It Works
- Your JavaScript (or Stimulus controller) calls
TurboDesktop.sendBridgeMessage() - The message is sent to the Rust shell via Tauri's invoke system
- Rust processes the message and can respond back to JavaScript
Built-in Components
| Component | What It Does |
|---|---|
notification |
Show native OS notifications (macOS, Windows, Linux) |
menu-item |
Register custom items in the native menu bar |
file-picker |
Open native file open/save dialogs |
badge |
Set the dock/taskbar badge count |
shortcut |
Register global keyboard shortcuts |
JavaScript API
Send a Bridge Message
// TurboDesktop is injected by the desktop shell — only available in the native app
if (typeof TurboDesktop !== "undefined") {
TurboDesktop.sendBridgeMessage("notification", "connect", {
title: "Task Completed!",
body: "Your task has been marked as done."
})
}
Stimulus Bridge Mixin
For Stimulus controllers, use the stimulusBridge() helper:
import { Controller } from "@hotwired/stimulus"
export default class extends TurboDesktop.stimulusBridge(Controller, "notification") {
connect() {
super.connect()
this.sendBridge("connect", { title: "My App" })
}
notify(event) {
this.sendBridge("connect", {
title: "New Message",
body: event.target.dataset.body
})
}
// Called when the native side responds
receiveBridge(message) {
console.log("Native says:", message)
}
}
Rails View Helpers
The turbo_desktop-rails gem provides a turbo_desktop_bridge helper that outputs the right data attributes:
<%%= tag.button "Export PDF",
**turbo_desktop_bridge("menu-item",
title: "Export PDF",
shortcut: "Cmd+E"
) %>
You can also use it inline with button_to:
<%%= button_to "Complete", task_path(task),
method: :patch,
data: {
**turbo_desktop_bridge("notification",
title: "Done!",
body: task.title
)
} %>
Notification Example
The example app includes a notification bridge controller:
// app/javascript/controllers/notification_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static values = {
title: { type: String, default: "Notification" },
body: { type: String, default: "" }
}
notify() {
if (typeof TurboDesktop !== "undefined") {
TurboDesktop.sendBridgeMessage("notification", "connect", {
title: this.titleValue,
body: this.bodyValue
})
}
}
}
Custom Components
You can create your own bridge components. Any component name that isn't built-in gets forwarded as a custom event:
// Web side
TurboDesktop.sendBridgeMessage("my-custom-component", "some-event", {
key: "value"
})
On the Rust side, you can listen for and handle these custom events.