Conditional Rendering and Lists in euv
Project Code:https://github.com/euv-dev/euv
euv is a Rust + WASM frontend UI framework that brings the power of reactive programming to web development. One of the most fundamental aspects of building dynamic user interfaces is the ability to conditionally render content and iterate over collections. In this article, we will explore euv's conditional rendering mechanisms — including if/else, match, and attribute-level conditionals — as well as its for loop list rendering capabilities.
Table of Contents
- if/else Conditional Rendering
- match Conditional Rendering
- Conditional Attribute Values
- Building a Tab Switcher
- List Rendering with for Loops
- Best Practices and Common Patterns
if/else Conditional Rendering
The simplest form of conditional rendering in euv is the if/else expression. It allows you to toggle the visibility of a piece of UI based on a reactive Signal<bool>.
Here is a basic example:
let show_details: Signal<bool> = use_signal(|| false);
html! {
primary_button { label: "Toggle" onclick: use_toggle(show_details) "Toggle" }
if { show_details.get() } { div { "Details visible" } } else { "" }
}
In this example, we create a boolean signal show_details initialized to false. The use_toggle utility function is bound to a button's onclick event, which flips the signal's value each time the button is clicked. When show_details is true, the div with the text "Details visible" is rendered; otherwise, an empty string "" is rendered.
Important: The else branch is mandatory in euv's if expressions. You cannot omit it. When you need to render nothing, use an empty string "" as the else body.
This pattern is ideal for simple show/hide toggles, such as expanding/collapsing sections, showing modal dialogs, or displaying loading indicators.
match Conditional Rendering
When you have more than two branches to choose from, euv's match expression provides a clean and exhaustive way to handle multiple conditions. The match expression evaluates a value and routes rendering to the appropriate branch.
let user_type: Signal<String> = use_signal(|| "guest".to_string());
html! {
match { user_type.get().as_str() } {
"guest" => { div { "Welcome, guest!" } }
"user" => { div { "Hello, user!" } }
_ => { div { "Welcome, administrator!" } }
}
}
In this example, the match expression checks the value of user_type and renders different welcome messages depending on whether the user is a "guest", a "user", or an administrator (the wildcard _ branch).
Important: Every match expression in euv must include a wildcard _ branch. This ensures exhaustive pattern matching — the compiler will warn you if you forget to handle a case. The wildcard branch acts as the default fallback.
The match expression is perfect for role-based UI, multi-step wizards, state machines, or any scenario where you need to render different content based on a single reactive value.
Conditional Attribute Values
Sometimes you don't want to conditionally render an entire element, but rather conditionally set its attributes — such as CSS classes or inline styles. euv supports conditional expressions directly within attribute values.
let is_active: Signal<bool> = use_signal(|| false);
html! {
div {
class: if { is_active.get() } { c_active() } else { c_inactive() }
style: {
color: if { is_active.get() } { "#4f46e5".to_string() } else { "inherit".to_string() };
border_bottom: if { is_active.get() } { "2px solid #4f46e5".to_string() } else { "2px solid transparent".to_string() };
}
"Tab item"
}
}
Here, the class attribute is conditionally set to either c_active() or c_inactive() based on the is_active signal. Similarly, the style block contains conditional values for color and border_bottom. When is_active is true, the element gets an indigo color and a bottom border; when false, it inherits the default color and gets a transparent border.
This pattern is extremely useful for styling interactive elements like tabs, buttons, navigation items, or any component whose appearance should change based on state.
Building a Tab Switcher
Combining conditional attribute values with match rendering, we can build a complete tab switcher component. This is one of the most common UI patterns in web applications.
let tab: Signal<String> = use_signal(|| "info".to_string());
html! {
div {
div {
class: c_tab_bar()
div {
class: if { tab.get() == "info" } { c_tab_item_active() } else { c_tab_item_inactive() }
onclick: move |_event: Event| { tab.set("info".to_string()); }
"Info"
}
div {
class: if { tab.get() == "settings" } { c_tab_item_active() } else { c_tab_item_inactive() }
onclick: move |_event: Event| { tab.set("settings".to_string()); }
"Settings"
}
}
match { tab.get().as_str() } {
"info" => { div { "Information content" } }
_ => { div { "Settings content" } }
}
}
}
Let's break this down:
-
Tab Bar: The outer
divwithc_tab_bar()class serves as the tab bar container. -
Tab Items: Each tab item is a
divwhose class is conditionally set based on whether it matches the currenttabsignal value. Theonclickhandler updates thetabsignal when clicked. -
Tab Content: The
matchexpression renders the appropriate content based on the current tab. Whentabis"info", it shows "Information content"; otherwise (the_wildcard), it shows "Settings content".
This pattern scales well — you can add more tabs by adding more tab item divs and corresponding match arms. The reactive system ensures that only the active tab's content is rendered, and the UI updates automatically when the signal changes.
List Rendering with for Loops
When you need to render a collection of items, euv provides the for loop syntax within the html! macro. This allows you to iterate over a reactive Signal<Vec<T>> and render each item.
Basic List Rendering
let items: Signal<Vec<String>> = use_signal(|| vec!["Learn Rust".to_string(), "Build UI".to_string()]);
html! {
ul {
for item in { items.get() } { li { item } }
}
}
In this example, we have a signal holding a vector of strings. The for loop iterates over the vector, rendering each string inside an li element within a ul. When the items signal changes (e.g., items are added or removed), the list automatically re-renders.
List Rendering with Indices
Sometimes you need to display the index of each item alongside its content. euv supports destructuring in for loops to access both the index and the value:
let items: Signal<Vec<String>> = use_signal(|| vec!["Learn Rust".to_string(), "Build UI".to_string()]);
html! {
ul {
for (index, item) in { items.get().iter().enumerate() } {
li { span { index } span { item } }
}
}
}
Here, iter().enumerate() provides both the index (a usize) and the item (a &String) for each element. The index is rendered in one span and the item text in another, giving you a numbered list effect.
This pattern is essential for rendering dynamic data such as search results, to-do lists, product catalogs, or any collection that may change at runtime.
Best Practices and Common Patterns
Here are some tips for working with conditional rendering and lists in euv:
-
Always include the
elsebranch: euv requires it. Use""for empty content. -
Always include the
_wildcard inmatch: This ensures exhaustive matching and prevents runtime errors. -
Use
matchfor multiple branches: When you have more than two conditions,matchis cleaner than nestedif/else. -
Keep conditional logic in signals: Move complex conditions into computed signals to keep your
html!macro clean and readable. -
Leverage conditional attributes: Instead of conditionally rendering two separate elements, consider using conditional
classorstylevalues on a single element. -
Use
forloops for dynamic lists: When rendering data from aSignal<Vec<T>>, theforloop is the idiomatic approach. It automatically re-renders when the underlying data changes.
Conclusion
euv provides a powerful and intuitive set of tools for conditional rendering and list iteration. The if/else expression handles simple toggles, match handles multi-branch logic, conditional attribute values enable dynamic styling, and for loops make light work of rendering collections. By combining these patterns, you can build rich, interactive user interfaces with clean, declarative code.
In the next article, we will explore event handling in euv — how to respond to user interactions, work with form inputs, and leverage the full range of browser events.
Project Code:https://github.com/euv-dev/euv
Top comments (0)