Browser API Access in euv
Project Code:https://github.com/euv-dev/euv
euv is a Rust + WASM frontend UI framework that compiles to WebAssembly and runs in the browser. While euv provides a rich set of abstractions for building user interfaces, there are times when you need to interact directly with the browser's native APIs. In this article, we will explore how to access the Window, Document, Location, and Storage APIs from within euv components, and discuss patterns for working with asynchronous operations.
Table of Contents
- Accessing the Window Object
- Working with the Document Object
- Location and Navigation
- Local Storage
- Practical Patterns
- Conclusion
Accessing the Window Object
The window() function is your entry point to all browser APIs in euv. It returns the global Window object, which serves as the root of the browser's JavaScript API hierarchy.
let win: Window = window().expect("no global window exists");
The window() function returns an Option<Window>, so you should handle the case where it might not be available (e.g., in server-side rendering contexts or Web Workers). In typical browser environments, it will always be available.
Once you have the Window reference, you can access virtually any browser API through it. The Window object provides methods and properties for:
- Document access
- Location and navigation
- Local and session storage
- Timers (
set_interval,set_timeout) - Event listeners
- Screen and viewport information
- And much more
Working with the Document Object
The Document object represents the web page loaded in the browser and serves as an entry point into the page's DOM tree. You can obtain it from the Window object:
let win: Window = window().expect("no global window exists");
let doc: Document = win.document().expect("should have a document");
The document() method returns an Option<Document>, so you should handle the case where the document might not be available. In practice, if you have a Window object, you will almost always have a Document as well.
With the Document reference, you can:
- Create new DOM elements
- Query existing elements
- Manipulate the DOM structure
- Access the document's title, URL, and other properties
The Document object bridges the gap between euv's virtual DOM and the actual browser DOM, giving you full control when you need it.
Location and Navigation
The Location object provides access to the current URL and methods for navigation. You can obtain it from the Window object:
let win: Window = window().expect("no global window exists");
let location: Location = win.location();
Once you have the Location reference, you can read and manipulate the URL:
let hash: String = location.hash().unwrap_or_default();
let _ = location.set_hash("#/about");
In this example:
-
location.hash()returns the current URL hash fragment (the part after#), or an empty string if there is no hash. Theunwrap_or_default()ensures we get a validStringeven when the hash is not present. -
location.set_hash("#/about")navigates to a new hash fragment. This is useful for single-page application (SPA) routing, where different hash values represent different views or pages.
The Location object also provides access to other URL components such as host, pathname, protocol, port, and search (query string), as well as methods like assign(), reload(), and replace() for full URL navigation.
Local Storage
The Storage interface provides access to the browser's localStorage mechanism, which allows you to persist data across page reloads and browser sessions. You can obtain it from the Window object:
let win: Window = window().expect("no global window exists");
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
The local_storage() method returns an Option<Storage>, so you should check whether storage is available before using it. In some environments (e.g., private browsing mode or restricted contexts), localStorage may not be available.
Once you have a Storage reference, you can perform the following operations:
if let Some(storage) = storage {
let _ = storage.set_item("key", "value");
let value: Option<String> = storage.get_item("key").unwrap_or_default();
let _ = storage.remove_item("key");
}
Let's break down these operations:
-
set_item("key", "value")stores a key-value pair in local storage. The value is always stored as a string. -
get_item("key")retrieves the value associated with a key. It returnsOption<String>, so you should handle the case where the key doesn't exist. -
remove_item("key")removes a key-value pair from local storage.
Local storage is ideal for persisting user preferences, caching data, or maintaining state across sessions. However, keep in mind that:
- Storage is limited to approximately 5-10 MB per origin (varies by browser).
- Data is stored as strings, so you will need to serialize and deserialize complex data structures.
- Local storage is synchronous, so it may block the main thread for large operations.
- Data is not encrypted, so you should never store sensitive information like passwords or tokens.
Practical Patterns
Combining Browser APIs with Reactive Signals
One of the most powerful patterns in euv is combining browser API access with reactive signals. For example, you can synchronize the URL hash with a signal to build a simple router:
let tab: Signal<String> = use_signal(|| {
let win: Window = window().expect("no global window exists");
let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
if hash == "#/settings" {
"settings".to_string()
} else {
"info".to_string()
}
});
html! {
div {
match { tab.get().as_str() } {
"info" => { div { "Information content" } }
_ => { div { "Settings content" } }
}
}
}
In this pattern, the initial signal value is derived from the current URL hash, ensuring that the UI state matches the URL on page load.
Persisting State to Local Storage
You can use watch! to automatically persist signal changes to local storage:
let name: Signal<String> = use_signal(|| {
let win: Window = window().expect("no global window exists");
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
storage.get_item("user_name").unwrap_or_default()
} else {
"".to_string()
}
});
// Later in your component, when name changes, persist it:
// watch!(name, |new_name: String| {
// if let Some(storage) = storage_signal.get() {
// let _ = storage.set_item("user_name", &new_name);
// }
// });
This pattern ensures that user data is automatically saved whenever the signal changes, providing a seamless persistence experience.
Reading the Document Title
You can access and modify the document title through the Document object:
let win: Window = window().expect("no global window exists");
let doc: Document = win.document().expect("should have a document");
// doc.set_title("New Page Title");
This is useful for updating the browser tab title based on the current view or state.
Conclusion
euv provides direct access to the browser's native APIs through the window() function and its associated objects. The Window object serves as the gateway to the Document, Location, and Storage APIs, enabling you to:
- Manipulate the DOM directly when needed
- Read and modify the URL for SPA routing
- Persist data across sessions with
localStorage - Access any other browser API through the
Windowobject
By combining these browser APIs with euv's reactive signal system, you can build powerful, feature-rich web applications that leverage the full capabilities of the browser platform.
In the next article, we will explore the Keep Alive pattern — a technique for preserving component state across tab switches using CSS display toggling, cleanup hooks, and timer management.
Project Code:https://github.com/euv-dev/euv
Top comments (0)