A Streamlit/Gradio equivalent for pure Rust. Write a plain Rust function, and RustView turns it into a live browser UI -- no HTML, no JavaScript, no frontend build step.
The project is under active development. The core widget set and layout system are usable today, but the API is not yet stable. Expect breaking changes before a 1.0 release.
Add the dependency to your Cargo.toml:
[dependencies]
rustview = "0.1"Or use cargo add:
cargo add rustviewWrite your app:
use rustview::prelude::*;
fn app(ui: &mut Ui) {
let name = ui.text_input("Your name", "World");
let times = ui.int_slider("Repeat", 1..=10);
for _ in 0..times {
ui.write(format!("Hello, {}!", name));
}
}
fn main() {
rustview::run(app);
}Run it:
cargo run
# opens http://127.0.0.1:8501RustView ships 56+ widgets across these categories:
| Category | Widgets |
|---|---|
| Input | text_input, int_slider, slider, checkbox, button, toggle, radio, select, selectbox, multi_select, text_area, number_input, int_input, color_picker, date_picker, file_upload, image_upload |
| Output | write, heading, subheading, caption, markdown, code, json, table, dataframe, metric, progress, spinner, divider, badge, link |
| Alerts | success, warning, info, error, toast |
| Media | image, audio, video, download_button |
| Layout | container, sidebar, columns, tabs, expander, row, modal, empty |
| Forms | form, form_submit_button |
| Charts | line_chart, bar_chart, scatter_chart, histogram |
| Theming | Theme struct with CSS custom properties |
Full API docs: docs/widgets.md
Four runnable examples are included:
cargo run --example hello # minimal text-in / text-out
cargo run --example counter # stateful counter with buttons
cargo run --example dashboard # multi-column layout with charts
cargo run --example showcase # every widget on a single pageuse rustview::server::RustViewConfig;
let config = RustViewConfig {
bind: "0.0.0.0:8080".parse().unwrap(),
title: "My Dashboard".into(),
session_ttl_secs: 3600,
max_upload_bytes: 10_000_000,
..Default::default()
};
rustview::run_with_config(app, config);Themes are customizable through a Theme struct:
use rustview::server::{RustViewConfig, Theme};
let config = RustViewConfig {
theme: Theme {
background: "#ffffff".into(),
foreground: "#1a1a1a".into(),
primary: "#0066ff".into(),
..Theme::default()
},
..Default::default()
};Every widget remembers its value across re-renders automatically. For
user-defined state, use get_state and set_state:
fn counter(ui: &mut Ui) {
let count = ui.get_state::<i64>("n", 0);
if ui.button("Increment") {
ui.set_state("n", count + 1);
}
ui.write(format!("Count: {}", ui.get_state::<i64>("n", 0)));
}For simple input-to-output functions, the Gradio-style Interface API avoids
writing any UI code:
use rustview::prelude::*;
fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
fn main() {
Interface::from_fn(greet)
.title("Greeter")
.description("Type a name to greet")
.launch();
}RustView uses a thin-client / server-rendered model:
- An Axum HTTP server runs the app function and maintains a virtual DOM per session.
- On each user interaction the server diffs the old and new trees and sends JSON patches over SSE or as a POST response.
- A small (~4 KB) vanilla JS shim in the browser applies patches and forwards events back to the server.
- Session state is stored in-memory with a configurable TTL (default 24 hours).
- The
#[cached]proc-macro can cache expensive computations across renders.
See docs/architecture.md for a detailed walkthrough.
The TestUi harness lets you unit-test apps without starting a server:
use rustview::testing::TestUi;
#[test]
fn test_counter() {
let mut t = TestUi::new();
t.run(|ui| {
let n = ui.get_state::<i64>("n", 0);
if ui.button("Inc") { ui.set_state("n", n + 1); }
ui.write(format!("Count: {}", ui.get_state::<i64>("n", 0)));
});
assert!(t.contains_text("Count: 0"));
t.click_button("Inc");
t.run(|ui| {
let n = ui.get_state::<i64>("n", 0);
if ui.button("Inc") { ui.set_state("n", n + 1); }
ui.write(format!("Count: {}", ui.get_state::<i64>("n", 0)));
});
assert!(t.contains_text("Count: 1"));
}The list below reflects what exists today and what is planned. Items may shift depending on community feedback.
Done
- Publish to crates.io
- Core widget set (56+ widgets across input, output, layout, charts)
- Immediate-mode rendering with virtual DOM diffing
- Session state and user-defined state
- SSE-based live updates
#[cached]proc-macro- Custom theming
- Interface mode (Gradio-style single-function UIs)
- TestUi harness for unit testing
Near-term
- Add accessibility attributes (ARIA roles, keyboard navigation)
- WebSocket transport option alongside SSE
- File download improvements (streaming large files)
- Stabilize the public API and release v0.1 as a proper crate
Medium-term
- Component system for reusable widget groups
- Persistent state backends (SQLite, Redis)
- Authentication and multi-user session isolation
- Client-side routing for multi-page apps
- More chart types (area, candlestick, heatmap)
Long-term
- Plugin API for third-party widgets
- Deployment helpers (Docker image, systemd unit)
- Optional WASM compilation for offline-capable apps
- Rust 1.75 or newer
- Edition 2021
See CONTRIBUTING.md for setup instructions, coding guidelines, and how to submit a pull request.