DEV Community

tengxgfyrz67s
tengxgfyrz67s

Posted on

Conditional-Rendering-and-Lists

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

  1. if/else Conditional Rendering
  2. match Conditional Rendering
  3. Conditional Attribute Values
  4. Building a Tab Switcher
  5. List Rendering with for Loops
  6. 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 { "" }
}
Enter fullscreen mode Exit fullscreen mode

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!" } }
    }
}
Enter fullscreen mode Exit fullscreen mode

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"
    }
}
Enter fullscreen mode Exit fullscreen mode

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" } }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's break this down:

  1. Tab Bar: The outer div with c_tab_bar() class serves as the tab bar container.
  2. Tab Items: Each tab item is a div whose class is conditionally set based on whether it matches the current tab signal value. The onclick handler updates the tab signal when clicked.
  3. Tab Content: The match expression renders the appropriate content based on the current tab. When tab is "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 } }
    }
}
Enter fullscreen mode Exit fullscreen mode

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 } }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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:

  1. Always include the else branch: euv requires it. Use "" for empty content.
  2. Always include the _ wildcard in match: This ensures exhaustive matching and prevents runtime errors.
  3. Use match for multiple branches: When you have more than two conditions, match is cleaner than nested if/else.
  4. Keep conditional logic in signals: Move complex conditions into computed signals to keep your html! macro clean and readable.
  5. Leverage conditional attributes: Instead of conditionally rendering two separate elements, consider using conditional class or style values on a single element.
  6. Use for loops for dynamic lists: When rendering data from a Signal<Vec<T>>, the for loop 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)