Building My First Leptos Web Application with Rust and WebAssembly

From a fresh Leptos project to a working reactive web application running locally on Debian.


Goal acheived

Today I started working with Leptos, a Rust framework for building reactive web applications.

The project is located at:

~/Projects/leptos-demo

I used two terminals:

  • Terminal 1: running cargo leptos watch
  • Terminal 2: used to edit the application source

This was useful because Leptos automatically watches the project and rebuilds the application whenever the source code changes.


1. Started with src/app.rs

The main component we worked with was:

#[component]
fn HomePage() -> impl IntoView {

This is a Leptos component written entirely in Rust.

Instead of writing a traditional JavaScript/HTML application, the UI is being described directly from Rust.


2. Created reactive state

The first important piece we worked with was:

let count = RwSignal::new(0);

This creates a reactive value initialized to 0.

The important thing about a reactive signal is that Leptos knows which parts of the interface depend on that value.


3. Added a button event

We then connected a button to the signal:

<button on:click=move |_| *count.write() += 1>
    "Clicked: " {count} " times"
</button>

This gave the application an interactive counter.

When I clicked the button, the browser changed from:

Clicked: 0 times

to:

Clicked: 1 times
Clicked: 2 times
Clicked: 3 times
Clicked: 4 times

and eventually:

Clicked: 5 times

The important part is that the page updated without a browser refresh.


4. Compiled Rust for the server and browser

One of the coolest parts of this exercise was watching Leptos build both sides of the application.

The watcher successfully built the server:

cargo build --package=leptos-demo

and the frontend:

--target=wasm32-unknown-unknown

Leptos then used:

wasm-bindgen

to generate the JavaScript/WASM necessary for the browser.

The final development server was running at:

http://127.0.0.1:3000

And the browser successfully displayed my application.


5. My first working Rust/WASM application

The final page currently looks simple:

My First Leptos App

Welcome to my Rust + Leptos project!

Clicked: 5 times

It isn’t visually complicated yet — and that’s intentional.

The goal of this first exercise was to understand the fundamental relationship between:

Rust
   ↓
Leptos Component
   ↓
Reactive Signal
   ↓
Event Handler
   ↓
WebAssembly
   ↓
Browser DOM

That’s a pretty significant first step into Rust web development.


6. Also introduced a Reset action

The next piece we started adding was a second button:

<button on:click=move |_| count.set(0)>
    " Reset "
</button>

This demonstrates another way of modifying the same reactive state.

The counter uses:

*count.write() += 1

to increment the value, while:

count.set(0)

sets it directly back to zero.

One small note for the blog: your last screenshot still showed the previous browser version without the Reset button, so I’d describe Reset as the next exercise we began implementing, rather than claiming it was fully verified in the browser yet.


The warning encountered

The Rust build produced this warning:

warning: the following packages contain code that will be rejected
by a future version of Rust: proc-macro-error2 v2.0.1

This did not prevent the application from compiling or running.

The important result was:

Finished `dev` profile

and:

Serving at http://127.0.0.1:3000

So for now, the warning is something to document rather than something that stopped the project.


Lesson learned

This first exercise gave me hands-on experience with several important concepts:

  • 🦀 Rust components
  • ⚡ Leptos reactivity
  • 🔢 RwSignal
  • 🖱️ Event handlers
  • 🌐 Server-side rendering
  • 🕸️ WebAssembly
  • 🔧 wasm-bindgen
  • 🔄 Automatic rebuilding with cargo leptos watch
  • 🖥️ Running a local Rust web server
  • 🌍 Connecting Rust application state to browser UI

Most importantly, I went from a project sitting on disk to a real interactive Rust web application running in my browser.