Comprehensive reference for every API, hook, and pattern in the framework.
From zero to a running Bueler app in under a minute.
$ rustup target add wasm32-unknown-unknown $ cargo install wasm-pack
$ cargo install --git https://github.com/IEvangelist/Bueler bueler-cli
$ bueler new my-app $ cd my-app
$ bueler dev # → Serving on http://localhost:8080 with live reload
$ bueler build # → Optimized WASM output in dist/
The bueler CLI handles scaffolding, development, and production builds.
| Command | Description | Key Flags |
|---|---|---|
bueler new <name> | Scaffold a new project with template, Cargo.toml, and wasm32 target. | --template |
bueler dev | Dev server with live reload, WASM compilation, and DWARF debug info. | --port |
bueler build | Release build with wasm-opt, tree-shaking, and gzip-ready output. | --release |
bueler serve | Serve the dist/ directory on a local HTTP server. | --port |
Fine-grained reactivity — no virtual DOM, no diffing.
let count = signal(0); let name = signal("Bueler".to_string());
let v = count.get(); // read count.set(10); // replace count.update(|n| *n += 1); // mutate in-place
create_effect(move || { log(&format!("count is {}", count.get())); });
let doubled = memo(move || count.get() * 2); // doubled.get() recomputes only when count changes
batch(|| { first.set("Jane".into()); last.set("Doe".into()); }); // effects run once, not twice
create_effect(move || { let a = count.get(); // tracked let b = untrack(|| other.get()); // not tracked });
watch( move || count.get(), move |new_val| log(&format!("changed to {new_val}")), );
on_mount(|| log("component mounted")); on_cleanup(|| log("component teardown"));
// parent provide_context(theme_signal); // any descendant let theme = use_context::<Signal<Theme>>();
JSX-like template syntax compiled at build time — zero runtime parsing.
view! { <div>"Hello, world!"</div> <br /> <span>"static text"</span> }
view! { <p>"Count: " {count}</p> }
view! { <div class="card">...</div> <div class={dynamic_class}>...</div> }
view! { <button on:click={move |_| count.update(|n| *n += 1)}> "Click me" </button> }
let text = signal("".to_string()); let checked = signal(false); view! { <input bind:value={text} /> <input type="checkbox" bind:checked={checked} /> }
view! { <div class:active={is_active.get()} class:hidden={!visible.get()}> "toggle me" </div> }
view! { {if logged_in.get() { view! { <p>"Welcome back!"</p> } } else { view! { <p>"Please log in."</p> } }} }
view! { <ul> {for item in items.get() { view! { <li>{item}</li> } }} </ul> }
// Use a component view! { <Counter initial={5} /> } // SVG elements work natively view! { <svg width="100" height="100"> <circle cx="50" cy="50" r={radius} /> </svg> }
Ready-made use_* utilities — each returns a reactive signal.
let theme = use_local_storage("theme", "dark".to_string()); // reads from localStorage on init, writes on every change
let ticks = use_interval(1000); // increments every second
let query = signal("".to_string()); let debounced = use_debounce(query, 300); let throttled = use_throttle(query, 200);
let (width, height) = use_window_size();
let (x, y) = use_scroll();
let (mx, my) = use_mouse();
let is_mobile = use_media_query("(max-width: 768px)");
let online = use_online(); // true when navigator.onLine
let dark = use_preferred_dark(); // reacts to OS theme
use_click_outside(dropdown_el, move || { open.set(false); });
let focused = use_focus(input_el); // true when focused
Low-level helpers for direct DOM manipulation.
let el = create_element("div"); let svg = create_svg_element("circle"); let txt = create_text_node("hello");
set_attribute(&el, "id", "main"); set_property(&el, "value", &"text".into()); set_style(&el, "color", "red"); toggle_class(&el, "active", true);
append_text(&el, "some text"); append_node(&parent, &child); clear_children(&el); set_inner_html(&el, "<b>bold</b>");
let el = query_selector("#app"); let b = body(); // document.body
add_event_listener(&el, "click", |e| { /* ... */ }); on_window_event("resize", |_| { /* ... */ }); on_document_event("keydown", |e| { /* ... */ });
let val = event_target_value(&event); // String let on = event_target_checked(&event); // bool
Manage the document <head> from Rust.
set_title("My Page — Bueler"); set_meta("description", "Built with Bueler");
Client-side SPA routing with hash or history mode.
let router = Router::new(RouterMode::Hash, vec![ route("/", || view! { <Home /> }), route("/about", || view! { <About /> }), route("/user/:id", || view! { <UserProfile /> }), ]);
view! { <nav> {link("/", "Home")} {nav_link("/about", "About", "nav-item")} </nav> {router.view()} }
navigate("/user/42");
let path = use_route(); // current path signal let id = use_param("id"); // single param let params = use_params(); // HashMap of all params
RouterMode::Hash // /#/about — works without server config RouterMode::History // /about — requires server-side fallback
Best-in-class UI components with builder APIs, built-in dark-theme CSS, and ARIA accessibility.
Components are included in the bueler crate — access via bueler::components::*.
Variants: primary, outline, danger, ghost. Sizes: small, medium, large. States: loading, disabled.
button("Save").primary().on_click(|_| save())
With label, placeholder, required, error message, signal binding.
text_input("Email").placeholder("you@example.com").bind(email).build()
textarea("Notes", notes_signal)
select("Language", &[("rs","Rust"),("ts","TypeScript")], lang)
checkbox("Subscribe to updates", subscribed)
card("Settings").body(content).footer(actions).build()
Severities: success, warning, error, info. Dismissible with signal.
alert("Saved!").success().build()
Backdrop click closes. ARIA dialog role.
modal(is_open).title("Confirm").body(content).build()
spinner() spinner_with_text("Loading...")
Animated bar, ARIA progressbar role.
progress(value_signal)
tabs(&[("Tab 1", view_fn), ("Tab 2", view_fn)])
badge("New", Severity::Success)
divider()
Loading placeholder with shimmer animation.
skeleton("100%", "20px")
Floating button that appears after scrolling down. Smooth-scrolls back to the top on click.
// Add to your app — positions fixed bottom-right scroll_to_top(300) // appears after scrolling 300px
Wrappers around browser timer APIs.
// One-shot delay let id = set_timeout(|| log("done"), 1000); clear_timeout(id); // Repeating interval let id = set_interval(|| log("tick"), 500); clear_interval(id); // Animation frame request_animation_frame(|ts| { log(&format!("frame at {ts}")); });
Thin wrappers around the Web Storage API.
local_storage_set("key", "value"); let val: Option<String> = local_storage_get("key");
Type-safe browser console bindings.
log("info message"); warn("warning message");
Read and write the URL hash fragment.
let hash = get_hash(); // e.g. "#section-1" set_hash("section-2"); // navigates to #section-2
Built-in distributed tracing with zero-cost abstraction when disabled.
use bueler::telemetry; telemetry::init(Config { service_name: "my-app", endpoint: Some("http://localhost:4317"), });
{
let _guard = telemetry::span("compute_layout");
// span ends when _guard is dropped
}
let resp = telemetry::traced_fetch("https://api.example.com/data").await; // Automatically propagates W3C traceparent header
let spans = telemetry::get_spans(); // Vec<Span> telemetry::clear_spans(); let stats = telemetry::get_stats(); // signal/effect counters
telemetry::set_hook(|event: HookEvent| { match event { HookEvent::SignalCreate(id) => { /* ... */ } HookEvent::EffectRun(id) => { /* ... */ } _ => {} } }); telemetry::clear_hook();
Production-grade fault tolerance built into the framework.
error_boundary( || view! { <RiskyComponent /> }, |err| view! { <p class="err">{err}</p> }, ); // or use the built-in styled card default_error_boundary(|| view! { <RiskyComponent /> });
let cfg = RetryConfig::exponential(3, 100); // 3 attempts, 100ms base let data = retry(cfg, || async { fetch_json("/api/data").await }).await; let fixed = RetryConfig::fixed(5, 200); // 5 attempts, 200ms each
let breaker = CircuitBreaker::new(CircuitConfig { failure_threshold: 5, reset_timeout_ms: 30_000, }); let result = breaker.call(|| async { fetch_json("/api").await }).await; breaker.reset(); // force back to Closed // States: CircuitState::Closed | Open | HalfOpen
let result = with_timeout(5000, fetch_json("/slow")).await; sleep(1000).await; // async delay
Struct-based components with the Component trait.
struct Counter { initial: i32, } impl Component for Counter { fn view(&self) -> View { let count = signal(self.initial); view! { <button on:click={move |_| count.update(|n| *n += 1)}> {count} </button> } } }
view! { <Counter initial={5} /> <Counter initial={0} /> }
Source-level Rust debugging in the browser.
bueler dev — builds with DWARF debug info embedded in the WASM binary..rs files appear in the file tree.# Build with debug info $ bueler dev # Chrome Sources panel shows: # file:// → src/lib.rs # Set breakpoints, step in/out, inspect locals. # Production strips all debug info: $ bueler build