Bueler Documentation

Comprehensive reference for every API, hook, and pattern in the framework.

1. Getting Started

From zero to a running Bueler app in under a minute.

Install the toolchain

$ rustup target add wasm32-unknown-unknown
$ cargo install wasm-pack

Install the Bueler CLI

$ cargo install --git https://github.com/IEvangelist/Bueler bueler-cli

Create a project

$ bueler new my-app
$ cd my-app

Run the dev server

$ bueler dev
# → Serving on http://localhost:8080 with live reload

Build for production

$ bueler build
# → Optimized WASM output in dist/

2. CLI Reference

The bueler CLI handles scaffolding, development, and production builds.

CommandDescriptionKey Flags
bueler new <name>Scaffold a new project with template, Cargo.toml, and wasm32 target.--template
bueler devDev server with live reload, WASM compilation, and DWARF debug info.--port
bueler buildRelease build with wasm-opt, tree-shaking, and gzip-ready output.--release
bueler serveServe the dist/ directory on a local HTTP server.--port

3. Core Reactivity

Fine-grained reactivity — no virtual DOM, no diffing.

signal(value) — create a reactive value

let count = signal(0);
let name = signal("Bueler".to_string());

Signal::get / set / update — read, write, mutate

let v = count.get();        // read
count.set(10);              // replace
count.update(|n| *n += 1); // mutate in-place

create_effect(f) — auto-tracking side effect

create_effect(move || {
    log(&format!("count is {}", count.get()));
});

memo(f) — derived / computed signal

let doubled = memo(move || count.get() * 2);
// doubled.get() recomputes only when count changes

batch(f) — coalesce multiple updates

batch(|| {
    first.set("Jane".into());
    last.set("Doe".into());
}); // effects run once, not twice

untrack(f) — read without subscribing

create_effect(move || {
    let a = count.get();             // tracked
    let b = untrack(|| other.get()); // not tracked
});

watch(source, callback) — react to changes (skips initial)

watch(
    move || count.get(),
    move |new_val| log(&format!("changed to {new_val}")),
);

on_mount(f) / on_cleanup(f) — lifecycle hooks

on_mount(|| log("component mounted"));
on_cleanup(|| log("component teardown"));

provide_context / use_context — dependency injection

// parent
provide_context(theme_signal);

// any descendant
let theme = use_context::<Signal<Theme>>();

4. View Macro

JSX-like template syntax compiled at build time — zero runtime parsing.

Elements & text

view! {
    <div>"Hello, world!"</div>
    <br />
    <span>"static text"</span>
}

Dynamic expressions

view! { <p>"Count: " {count}</p> }

Static & dynamic attributes

view! {
    <div class="card">...</div>
    <div class={dynamic_class}>...</div>
}

Events — on:event

view! {
    <button on:click={move |_| count.update(|n| *n += 1)}>
        "Click me"
    </button>
}

Two-way binding — bind:value, bind:checked

let text = signal("".to_string());
let checked = signal(false);
view! {
    <input bind:value={text} />
    <input type="checkbox" bind:checked={checked} />
}

Class toggling — class:name

view! {
    <div class:active={is_active.get()} class:hidden={!visible.get()}>
        "toggle me"
    </div>
}

Conditional rendering

view! {
    {if logged_in.get() {
        view! { <p>"Welcome back!"</p> }
    } else {
        view! { <p>"Please log in."</p> }
    }}
}

List rendering

view! {
    <ul>
        {for item in items.get() {
            view! { <li>{item}</li> }
        }}
    </ul>
}

Components & SVG

// 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>
}

5. Reactive Hooks

Ready-made use_* utilities — each returns a reactive signal.

use_local_storage(key, default) — persistent signal

let theme = use_local_storage("theme", "dark".to_string());
// reads from localStorage on init, writes on every change

use_interval(ms) — reactive timer tick

let ticks = use_interval(1000); // increments every second

use_debounce / use_throttle — rate-limited signals

let query = signal("".to_string());
let debounced = use_debounce(query, 300);
let throttled = use_throttle(query, 200);

use_window_size() — reactive viewport dimensions

let (width, height) = use_window_size();

use_scroll() — reactive scroll position

let (x, y) = use_scroll();

use_mouse() — reactive mouse coordinates

let (mx, my) = use_mouse();

use_media_query(query) — CSS media match

let is_mobile = use_media_query("(max-width: 768px)");

use_online() — network status

let online = use_online(); // true when navigator.onLine

use_preferred_dark() — prefers-color-scheme

let dark = use_preferred_dark(); // reacts to OS theme

use_click_outside(el, handler) — click outside detection

use_click_outside(dropdown_el, move || {
    open.set(false);
});

use_focus(el) — focus tracking

let focused = use_focus(input_el); // true when focused

6. DOM Utilities

Low-level helpers for direct DOM manipulation.

Element creation

let el = create_element("div");
let svg = create_svg_element("circle");
let txt = create_text_node("hello");

Attributes & styling

set_attribute(&el, "id", "main");
set_property(&el, "value", &"text".into());
set_style(&el, "color", "red");
toggle_class(&el, "active", true);

Tree manipulation

append_text(&el, "some text");
append_node(&parent, &child);
clear_children(&el);
set_inner_html(&el, "<b>bold</b>");

Query & globals

let el = query_selector("#app");
let b = body(); // document.body

Events

add_event_listener(&el, "click", |e| { /* ... */ });
on_window_event("resize", |_| { /* ... */ });
on_document_event("keydown", |e| { /* ... */ });

Form helpers

let val = event_target_value(&event);   // String
let on = event_target_checked(&event);  // bool

8. Routing

Client-side SPA routing with hash or history mode.

Define routes

let router = Router::new(RouterMode::Hash, vec![
    route("/",          || view! { <Home /> }),
    route("/about",     || view! { <About /> }),
    route("/user/:id",  || view! { <UserProfile /> }),
]);

Render the outlet

view! {
    <nav>
        {link("/", "Home")}
        {nav_link("/about", "About", "nav-item")}
    </nav>
    {router.view()}
}

Programmatic navigation

navigate("/user/42");

Route params

let path = use_route();           // current path signal
let id = use_param("id");        // single param
let params = use_params();        // HashMap of all params

Router modes

RouterMode::Hash     // /#/about  — works without server config
RouterMode::History  // /about    — requires server-side fallback

9. Pre-built Components

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::*.

Button

Variants: primary, outline, danger, ghost. Sizes: small, medium, large. States: loading, disabled.

button("Save").primary().on_click(|_| save())

TextInput

With label, placeholder, required, error message, signal binding.

text_input("Email").placeholder("you@example.com").bind(email).build()

TextArea

textarea("Notes", notes_signal)

Select

select("Language", &[("rs","Rust"),("ts","TypeScript")], lang)

Checkbox

checkbox("Subscribe to updates", subscribed)

Card

card("Settings").body(content).footer(actions).build()

Alert

Severities: success, warning, error, info. Dismissible with signal.

alert("Saved!").success().build()

Modal

Backdrop click closes. ARIA dialog role.

modal(is_open).title("Confirm").body(content).build()

Spinner

spinner()
spinner_with_text("Loading...")

Progress

Animated bar, ARIA progressbar role.

progress(value_signal)

Tabs

tabs(&[("Tab 1", view_fn), ("Tab 2", view_fn)])

Badge

badge("New", Severity::Success)

Divider

divider()

Skeleton

Loading placeholder with shimmer animation.

skeleton("100%", "20px")

Scroll to Top

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

10. Timers

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}"));
});

11. Storage

Thin wrappers around the Web Storage API.

local_storage_set("key", "value");
let val: Option<String> = local_storage_get("key");

12. Console

Type-safe browser console bindings.

log("info message");
warn("warning message");

13. Location

Read and write the URL hash fragment.

let hash = get_hash();   // e.g. "#section-1"
set_hash("section-2");   // navigates to #section-2

14. OpenTelemetry

Built-in distributed tracing with zero-cost abstraction when disabled.

telemetry::init(Config) — enable auto-tracing

use bueler::telemetry;

telemetry::init(Config {
    service_name: "my-app",
    endpoint: Some("http://localhost:4317"),
});

telemetry::span(name) — manual span (RAII guard)

{
    let _guard = telemetry::span("compute_layout");
    // span ends when _guard is dropped
}

telemetry::traced_fetch(url) — HTTP with W3C traceparent

let resp = telemetry::traced_fetch("https://api.example.com/data").await;
// Automatically propagates W3C traceparent header

Inspect & stats

let spans = telemetry::get_spans();   // Vec<Span>
telemetry::clear_spans();
let stats = telemetry::get_stats();   // signal/effect counters

Runtime hooks

telemetry::set_hook(|event: HookEvent| {
    match event {
        HookEvent::SignalCreate(id) => { /* ... */ }
        HookEvent::EffectRun(id)    => { /* ... */ }
        _ => {}
    }
});
telemetry::clear_hook();

15. Resiliency

Production-grade fault tolerance built into the framework.

error_boundary — catch panics

error_boundary(
    || view! { <RiskyComponent /> },
    |err| view! { <p class="err">{err}</p> },
);
// or use the built-in styled card
default_error_boundary(|| view! { <RiskyComponent /> });

retry — async retry with backoff

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

CircuitBreaker — prevent cascading failure

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

with_timeout / sleep — async timing

let result = with_timeout(5000, fetch_json("/slow")).await;
sleep(1000).await; // async delay

16. Component System

Struct-based components with the Component trait.

Define a component

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>
        }
    }
}

Use in view!

view! {
    <Counter initial={5} />
    <Counter initial={0} />
}

17. Debugging

Source-level Rust debugging in the browser.

  1. Run bueler dev — builds with DWARF debug info embedded in the WASM binary.
  2. Open Chrome and install the "C/C++ DevTools Support (DWARF)" extension.
  3. Open DevTools → Sources tab — your .rs files appear in the file tree.
  4. Set breakpoints, step through code, and inspect variables just like native Rust debugging.
# 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