How to Control Webview Navigation with Tauri Commands: Reload, Back, and Forward
You can control webview navigation in Tauri by registering Rust commands that use eval() to execute JavaScript navigation APIs like window.location.reload() and window.history.back() inside the webview.
The lencx/ChatGPT desktop application demonstrates a robust pattern for controlling embedded webview navigation using Tauri commands. By exposing Rust functions that evaluate JavaScript directly in the webview context, the application enables seamless reload, back, and forward functionality from the native UI. This architecture bridges the React frontend and the underlying WebKit webview through Tauri's command system.
Architecture of Webview Navigation Commands
The navigation system relies on three coordinated components: command registration in the Rust entry point, implementation in a dedicated commands module, and invocation from the frontend via Tauri's JavaScript API.
Command Registration in main.rs
In src-tauri/src/main.rs, the Tauri builder registers the navigation handlers using generate_handler!. This exposes the Rust functions to the frontend runtime:
tauri::Builder::default()
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_dialog::init())
.invoke_handler(tauri::generate_handler![
cmd::view_reload,
cmd::view_go_forward,
cmd::view_go_back,
// … other commands
])
.run(tauri::generate_context!())
.expect("error while running lencx/ChatGPT application");
Command Implementation in cmd.rs
The actual navigation logic resides in src-tauri/src/core/cmd.rs. Each command obtains the AppHandle, retrieves the window labeled "core", fetches the webview named "main", and executes the corresponding JavaScript navigation method via eval():
Reload functionality uses window.location.reload():
#[command]
pub fn view_reload(app: AppHandle) {
app.get_window("core")
.unwrap()
.get_webview("main")
.unwrap()
.eval("window.location.reload()")
.unwrap();
}
Forward navigation uses window.history.forward():
#[command]
pub fn view_go_forward(app: AppHandle) {
app.get_window("core")
.unwrap()
.get_webview("main")
.unwrap()
.eval("window.history.forward()")
.unwrap();
}
Back navigation uses window.history.back():
#[command]
pub fn view_go_back(app: AppHandle) {
app.get_window("core")
.unwrap()
.get_webview("main")
.unwrap()
.eval("window.history.back()")
.unwrap();
}
Frontend Invocation via Tauri API
The React frontend invokes these commands using @tauri-apps/api/core. In src/view/Titlebar.tsx, button click handlers call invoke() with the command names:
import { invoke } from '@tauri-apps/api/core';
const handleRefresh = () => {
invoke('view_reload');
};
const handleGoForward = () => {
invoke('view_go_forward');
};
const handleGoBack = () => {
invoke('view_go_back');
};
These handlers are bound to the title bar navigation icons, creating a seamless native navigation experience.
Implementation Guide for Custom Navigation
Accessing Webviews by Label
The lencx/ChatGPT implementation targets specific window and webview labels. The get_window("core") call retrieves the main application window, while get_webview("main") targets the primary content webview. Ensure your tauri.conf.json defines these labels, or modify the code to match your configuration.
Error Handling Considerations
The example code uses .unwrap() for brevity. In production applications, implement proper error handling to manage cases where the window or webview might not be available:
#[command]
pub fn view_reload(app: AppHandle) -> Result<(), String> {
let window = app.get_window("core").ok_or("Window not found")?;
let webview = window.get_webview("main").ok_or("Webview not found")?;
webview.eval("window.location.reload()").map_err(|e| e.to_string())?;
Ok(())
}
Extending Navigation Capabilities
You can extend this pattern to support additional navigation actions by modifying the JavaScript string passed to eval(). For example, to navigate to a specific URL:
#[command]
pub fn view_navigate(app: AppHandle, url: String) {
app.get_window("core")
.unwrap()
.get_webview("main")
.unwrap()
.eval(&format!("window.location.href = '{}'", url))
.unwrap();
}
Summary
- Command registration occurs in
src-tauri/src/main.rsusingtauri::generate_handler!to expose Rust functions to the frontend. - Navigation implementation in
src-tauri/src/core/cmd.rsusesapp.get_window("core").get_webview("main").eval()to execute JavaScript navigation APIs. - JavaScript evaluation enables access to standard browser APIs including
window.location.reload(),window.history.back(), andwindow.history.forward(). - Frontend integration uses
invoke()from@tauri-apps/api/coreto trigger navigation from React components as demonstrated insrc/view/Titlebar.tsx. - Window and webview labels must match between your Rust code and Tauri configuration (the ChatGPT app uses
"core"for the window and"main"for the webview).
Frequently Asked Questions
How do I reload a Tauri webview from Rust?
Register a command that retrieves your webview instance and call eval() with window.location.reload(). In the lencx/ChatGPT codebase, the view_reload function in src-tauri/src/core/cmd.rs demonstrates this pattern by targeting the "main" webview within the "core" window.
Can I navigate back and forward in a Tauri webview using commands?
Yes. Expose commands that evaluate window.history.back() and window.history.forward() in the webview context. The ChatGPT application implements view_go_back and view_go_forward commands in src-tauri/src/core/cmd.rs, which are bound to the title bar navigation buttons in the React frontend.
What is the difference between using Tauri commands versus frontend JavaScript for navigation?
Tauri commands execute in the Rust backend with access to the full Tauri API, allowing navigation triggers from native menus, keyboard shortcuts, or system events. Frontend JavaScript navigation only works when the webview content is focused and executable. The command pattern also enables navigation when the webview might not have JavaScript execution context available or when triggered from the native application menu.
How do I target a specific webview when multiple exist in a Tauri window?
Use the get_webview() method with the specific label defined in your configuration. The lencx/ChatGPT application uses get_webview("main") to target the primary content webview, distinguishing it from any auxiliary webviews that might exist in the "core" window. Always ensure the webview label matches exactly between your Rust code and tauri.conf.json.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →