Getting Started
tauri-remote-ui has two halves that work together:
- a Rust crate (
tauri-remote-ui) that registers the Tauri plugin and runs the HTTP/WebSocket server, and - an npm package (
tauri-remote-ui) that providesinvoke/listenshims for your frontend.
| Resource | Link |
|---|---|
| Crate | crates.io/crates/tauri-remote-ui |
| API docs (Rust) | docs.rs/tauri-remote-ui |
| npm package | npmjs.com/package/tauri-remote-ui |
| Source & issues | github.com/DraviaVemal/tauri-remote-ui |
Requirements
Section titled “Requirements”- Tauri 2.x
- Rust 1.77.2 or newer
- A bundled frontend (the plugin serves your built assets, e.g.
frontendDist)
1. Install the packages
Section titled “1. Install the packages”-
Add the Rust crate to your Tauri app (
src-tauri):Terminal window cargo add tauri-remote-ui -
Add the npm package to your frontend:
Terminal window npm install tauri-remote-uiTerminal window yarn add tauri-remote-uiTerminal window pnpm add tauri-remote-ui
2. Register the plugin
Section titled “2. Register the plugin”Add the plugin in your Tauri builder, then expose commands to start and stop the remote UI server from the frontend.
use tauri::AppHandle;use tauri_remote_ui::{RemoteUiConfig, RemoteUiExt};
#[tauri::command]async fn enable_server(app: AppHandle) -> Result<(), String> { app.start_remote_ui(RemoteUiConfig::default().set_port(Some(9090))) .await .map_err(|e| e.to_string())}
#[tauri::command]async fn disable_server(app: AppHandle) -> Result<(), String> { app.stop_remote_ui().await.map_err(|e| e.to_string())}
pub fn run() { tauri::Builder::default() .plugin(tauri_remote_ui::init()) .invoke_handler(tauri::generate_handler![enable_server, disable_server]) .run(tauri::generate_context!()) .expect("error while running tauri application");}3. Use the frontend shims
Section titled “3. Use the frontend shims”Replace @tauri-apps/api imports with the matching tauri-remote-ui entry
points. The shims call native Tauri IPC when inside the webview and
transparently fall back to a WebSocket transport when loaded through a browser.
import { invoke } from "tauri-remote-ui/api/core";import { listen } from "tauri-remote-ui/api/event";
await listen<{ result: number }>("counter", (event) => { console.log("counter is now", event.payload.result);});
await invoke("increment");4. Emit events from Rust
Section titled “4. Emit events from Rust”To deliver events to both the native window and any connected remote client,
import EmitterExt and call its async
emit on a WebviewWindow:
use tauri::Manager;use tauri_remote_ui::EmitterExt;
let window = app.get_webview_window("main").unwrap();window.emit("counter", serde_json::json!({ "result": 42 })).await?;5. Develop with a dev server (optional)
Section titled “5. Develop with a dev server (optional)”When running a frontend dev server (Vite, etc.), proxy the plugin’s endpoints so the browser can reach the running Tauri host:
export default defineConfig({ server: { port: 3001, proxy: { "/remote_ui_info": { target: "http://localhost:9090", changeOrigin: true }, "/remote_ui_disconnect": { target: "http://localhost:9090", changeOrigin: true }, "/remote_ui_ws": { target: "http://localhost:9090", changeOrigin: true, ws: true }, }, },});What happens next
Section titled “What happens next”- Start your app and trigger
enable_server. - The native window shows a blocking screen listing every URL the server is reachable on (unless you keep the app UI active).
- Open one of those URLs in a browser — your app loads and is fully interactive.
- Closing the tab redirects to the disconnect screen; restart or call
disable_serverto resume normal operation.
Continue with Concepts to understand how the bridge works, or jump to Configuration and Security.
Have an idea or question? Start a thread in the Discussion Channel.