Leptos
amethystate-leptos bridges reactive state to Leptos signals. Each field is accessed via hooks that return native Leptos types — ReadSignal<T> and SignalSetter<T>. Components re-render only when the specific fields they read change.
Field handles are Copy indices, so they can be passed down through component props without cloning or lifetimes.
Note: This integration is designed for WASM frontends (CSR), primarily for Tauri applications.
[dependencies]amethystate-leptos = { version = "*", features = ["tauri"] }Defining state
Section titled “Defining state”The frontend structs are generated automatically from your backend types via amethystate-codegen. Do not write them by hand.
// GENERATED AUTOMATICALLY. DO NOT EDIT.use amethystate_arena::amethystate_framework_arena;
#[amethystate_framework_arena]#[::amethystate::amethystate(prefix = "settings", target = "tauri-wasm")]pub struct AppSettings { pub username: String, pub counter: i32, #[amestate(nested)] pub theme: Theme,}See the Tauri integration chapter for codegen setup.
Provider & Initialization
Section titled “Provider & Initialization”State is loaded asynchronously over IPC. Wrap your app in amethystateProvider and declare which slices to load with preload_slices!. Rendering is suspended until all slices are ready.
use amethystate::tauri::TauriBackend;use amethystate_leptos::{amethystateProvider, preload_slices};use leptos::prelude::*;
use crate::bindings::AppSettings;
#[component]pub fn App() -> impl IntoView { let backend = TauriBackend::new();
view! { <amethystateProvider backend=backend init=preload_slices!(AppSettings) fallback=|| view! { <p>"Loading state..."</p> } > <MainLayout /> </amethystateProvider> }}Accessing state
Section titled “Accessing state”Use use_amethystate::<S>() inside a component to get the root handle for a slice. The handle is a Copy struct with a field for each state field, which you can pass down as props.
#[component]fn MainLayout() -> impl IntoView { let state = use_amethystate::<AppSettings>();
view! { <SettingsEditor state=state /> }}
#[component]fn SettingsEditor(state: Handle<AppSettings>) -> impl IntoView { // state.username, state.counter, state.theme — all Copy handles}Handle<S> is a type alias for the generated handle type. Use it in prop declarations.
use_field
Section titled “use_field”Returns a (ReadSignal<T>, SignalSetter<T>) pair for a writable field. The setter applies the change optimistically on the frontend and persists it to the backend asynchronously. If the backend returns an error, the value is reset to the last confirmed state.
let (username, set_username) = use_field(state.username);
view! { <input prop:value=username on:input=move |e| set_username.set(event_target_value(&e)) />}use_read_only_field
Section titled “use_read_only_field”Returns a ReadSignal<T> for a read-only field or a lookup field without export_mut.
let host = use_read_only_field(state.host);
view! { <p>"Connected to: " {host}</p>}use_pipeline
Section titled “use_pipeline”Derives a signal from one or more fields. The pipeline recomputes automatically when any input changes. It is cleaned up when the component unmounts.
let address = use_pipeline(move || { (state.host, state.port) .pipe() .map(|(h, p)| format!("{h}:{p}")) .dedupe()});
view! { <p>"Proxy Address: " <strong>{address}</strong></p>}use_map
Section titled “use_map”Returns a MapSignal<K, V> for a writable ReactiveMap field. The signal holds a snapshot of all entries and updates on any external change. It also exposes set_or_create, remove, and clear.
let map = use_map(state.env);
let on_add = move |_| { map.set_or_create("NEW_KEY".to_string(), "value".to_string());};
let on_remove = Callback::new(move |key: String| { map.remove(key);});
view! { <For each=move || map.entries.get() key=|(k, _)| k.clone() children=move |(k, v)| { let k_clone = k.clone(); view! { <div> <code>{k} " = " {v}</code> <button on:click=move |_| on_remove.run(k_clone.clone())>"Remove"</button> </div> } } /> <button on:click=on_add>"Add Key"</button>}use_map_entry
Section titled “use_map_entry”Subscribes to a single key in a ReactiveMap, returning a ReadSignal<Option<V>>.
let proxy_port = use_map_entry(state.env, "HTTP_PROXY".to_string());
view! { <p>"Proxy Port: " {move || proxy_port.get().unwrap_or_else(|| "Not set".into())}</p>}Examples
Section titled “Examples”tauri-leptos— Full Tauri v2 app with a Leptos WASM frontend.