Skip to main content
Version: Next

Conditional rendering

If blocks

To conditionally render some markup, we wrap it in an if block:

use yew::prelude::*;

html! {
if true {
<p>{ "True case" }</p>
}
};

Match blocks

match expressions work directly in html!, following the same pattern as if/else:

use yew::prelude::*;

let value: Option<String> = Some("hello".into());

html! {
match value {
Some(text) => <p>{text}</p>,
None => <p>{"Nothing here"}</p>,
}
};

Arms with a single element can omit braces. Arms with multiple children or let bindings require braces.

match supports all standard Rust patterns including OR-patterns (A | B), destructuring, and if guards. Exhaustiveness is checked by the Rust compiler.

Loops inside if/match bodies

for, while, and loop inside an if/else if/else/match-arm body follow the same rules they do at the top level of html!, with one caveat: if the loop body is fully Rust-parseable (no html elements anywhere inside), the macro takes the loop as a Rust statement instead of html-control-flow.

The most common way to hit this is a loop whose only child is a bare {expr} block:

// Compiles. The for is at the top level, parsed as html-`for`.
html! {
for _ in 0..9 {
{my_foo}
}
}

// Does NOT compile. The for is inside an `if`, parsed as a Rust statement;
// rustc then complains that the body returns a value where `()` is expected.
html! {
if condition {
for _ in 0..9 {
{my_foo}
}
}
}

Wrap the child in an html element to keep it as html-for:

html! {
if condition {
for _ in 0..9 {
<span>{my_foo}</span>
}
}
}

See Lists for the full set of workarounds.