Your First WaterUI App
Now that your development environment is set up, let's build your first interactive WaterUI application! We'll create a counter app that demonstrates the core concepts of views, state management, and user interaction.
What We'll Build
Our counter app will feature:
- A display showing the current count
- Buttons to increment and decrement the counter
- A reset button
- Dynamic styling based on the counter value
By the end of this chapter, you'll understand:
- How to create interactive views
- How to manage reactive state
- How to handle user events
- How to compose views together
Setting Up the Project
Create a new project for our counter app:
cargo new counter-app
cd counter-app
Update your Cargo.toml:
Filename: Cargo.toml
[package]
name = "counter-app"
version = "0.1.0"
edition = "2024"
[dependencies]
waterui = { path = "../" }
Building the Counter Step by Step
Let's build our counter app incrementally, learning WaterUI concepts along the way.
Step 1: Basic Structure
Start with a simple view structure. Since our initial view doesn't need state, we can use a function:
Filename: src/main.rs
use waterui::prelude::*;
fn counter() -> impl View {
"Counter App"
}
fn main() {
// Backend-specific initialization will be added here
// For now, we just define the view
}
Run this to make sure everything works:
cargo run
You should see a window with "Counter App" displayed.
Step 2: Adding Layout
Now let's add some layout structure using stacks:
use waterui::prelude::*;
fn counter() -> impl View {
vstack((
"Counter App",
"Count: 0",
))
}
Note:
vstackcreates a vertical stack of views. We'll learn abouthstack(horizontal) andzstack(overlay) later.
Step 3: Adding Reactive State
Now comes the exciting part - let's add reactive state! We'll use the re-exported binding helper together with Binding's convenience methods and the text! macro for reactive text:
use waterui::prelude::*;
use waterui::reactive::binding;
fn counter() -> impl View {
let count = binding(0);
vstack((
"Counter App",
// Use text! macro for reactive text
text!("Count: {count}"),
hstack((
button("- Decrement").action_with(&count, |count| count.decrement(1)),
button("+ Increment").action_with(&count, |count| count.increment(1)),
)),
))
}
Run this and try clicking the buttons! The counter should update in real-time.
Understanding the Code
Let's break down the key concepts introduced:
Reactive State with binding
let count = binding(0);
This creates a reactive binding with an initial value of 0. When this value changes, any UI elements that depend on it will automatically update.
Reactive Text Display
// ✅ Use the text! macro for reactive display
text!("Count: {count}")
- The
text!macro automatically handles reactivity - The text will update whenever
countchanges
Event Handling
button("- Decrement").action_with(&count, |count| count.decrement(1))
.action_with()attaches an event handler with captured stateBinding<i32>::decrementandBinding<i32>::incrementprovide ergonomic arithmetic updates without manual closures
Layout with Stacks
vstack((...)) // Vertical stack
hstack((...)) // Horizontal stack
Stacks are the primary layout tools in WaterUI, allowing you to arrange views vertically or horizontally.