Building Nested HTML

In the previous subchapter, we were able to render

<input />

Let's do something more complicated. Let's render

<div>
	<input />
</div>
use async_ui_web::html::{Div, Input}; // import Div and Input components

async fn my_input_field() {
    let div = Div::new();
    let input = Input::new();

    // render the UI!
    div.render(
        input.render(), // input is inside the div
    )
    .await;
}

Notice that there is only one .await in the example above.

// ❌❌ this wouldn't work
div.render(
	input.render().await
	//             👆👆
	// this await above is incorrect
).await;

It is very important to understand why using two awaits here is incorrect. The two concepts behind this rule are core concepts in Async UI.

.render(_) wraps its argument Future

The signature of div.render(_) is

fn render<F: Future>(&self, c: F) -> impl Future<Output = F::Output>;

It takes a Future object and returns a "wrapped" Future object. The new Future places a <div> on the screen, and if the inner Future put anything on the screen, that thing will appear inside the <div>.

Our input.render() is a Future that puts an <input> on the screen. We wrap it with div.render(_), giving us

<div>
	<input />
</div>

UI Futures are long-running

input.render() returns a Future object that never finishes. If we await it, our code would just be stuck there.

Why does the Future never finish?

The <input> element stays on the screen for as long as the Future is running. We wouldn't want the element to suddenly disappear!

In later chapters, we will learn how to remove rendered elements.

Does div.render(_) also never finish?

div.render(_) finishes when the inner Future finishes. This is why we say .render(_) "wraps" the inner Future.

In our case, though, the inner Future never finishes anyway

Why does div.render(_) take an argument while input.render() doesn't?

Per the HTML spec, <div> elements are allowed to have children, while <input> elements are not.