Building UIs with RSX

Dioxus renders to HTML, if you are not familiar with HTML, this guide will help you get started with the basics. For more detail, the MDN docs are a great resource.

Text Nodes

Any content surrounded by quotes is rendered as a text node in rsx:

src/building_uis_with_rsx.rs
rsx! {
    "Hello world"
}
Hello world

You can include formatted segments inside of the text just like the format! macro:

src/building_uis_with_rsx.rs
let user = use_signal(|| User {
    name: "Dioxus".to_string(),
});
rsx! {
    // Unlike the format macro, you can include many expressions inline in the formatted text
    "Hello {user.read().name}"
}
Hello Dioxus

Elements

The most basic building block of HTML is an element. In rsx, you can create elements with the name and then curly braces. One of the most common elements is the input element. The input element creates an interactive input box:

src/building_uis_with_rsx.rs
rsx! {
    input {}
}

Bonus: web components

src/building_uis_with_rsx.rs
rsx! {
    my-web-component {}
}

Attributes

Attributes provide extra information about an element. You can specify attributes in dioxus inside an element's braces by typing the name of the attribute, a colon, and then the value (typically a formatted string). We can use an attribute to set the type of an input element. The default type is text which shows a text input box, but we can set it to number to only accept numbers:

src/building_uis_with_rsx.rs
rsx! {
    input { type: "number" }
}

Just like text nodes, attributes can include formatted segments. We can set the value of the input element to a signal to control it:

src/building_uis_with_rsx.rs
let mut value = use_signal(|| "Hello world".to_string());
rsx! {
    input { value: "{value}" }
}

Conditional Attributes

You can conditionally set an attribute by setting the attribute value to an unterminated if statement. If the if statement evaluates to true, the attribute will be set:

src/building_uis_with_rsx.rs
let number_type = use_signal(|| false);
rsx! {
    input { type: if number_type() { "number" } }
}

Event Listeners

Event listeners allow you to respond to user input. In rsx, event handlers always start with on. The syntax is the same as normal attributes, but event handlers only accept a closure that responds to the event. We can attach an event listener to the oninput event of the input element to listen for changes to the input:

src/building_uis_with_rsx.rs
let mut value = use_signal(|| "Hello world".to_string());
rsx! {
    input {
        oninput: move |event| value.set(event.value()),
        value: "{value}"
    }
}

Children

You can add children to an element after all attributes and event listeners. Elements can accept text, components or other elements as children. We can add a div element around our input to center it:

src/building_uis_with_rsx.rs
rsx! {
    div {
        // display sets the layout mode of the element
        display: "flex",
        // justify-content centers the element horizontally
        justify_content: "center",
        input {
            type: "number"
        }
    }
}

Loops

You can insert for loops directly in rsx. The body of the loop accepts any number of children that will be rendered with each iteration of the loop. The ul element in html renders an unordered list with any number of li (list item) elements. We can use those two elements to render a list of items in a loop:

src/building_uis_with_rsx.rs
let mut items = use_signal(|| vec!["Hello", "Dioxus"]);

rsx! {
    ul {
        for item in items.iter() {
            li { "{item}" }
        }
    }
}
  • Hello
  • Dioxus

Each item in your list should have unique value that is stable across rerenders called a key. Keys are used to identify how items move while diffing. Without keys, it is easy to accidentally lose or move state when you reorder items in a list. We can add keys to our list items by using the key attribute:

src/building_uis_with_rsx.rs
let mut items = use_signal(|| vec!["Hello", "Dioxus"]);

rsx! {
    ul {
        for item in items.iter() {
            li { key: "{item}", "{item}" }
        }
    }
}
  • Hello
  • Dioxus

If Statements

You can also use if/else statements in rsx. Each branch of the if statement accepts child nodes that will be rendered if the condition is true. We can use the if statement to conditionally render a login screen:

src/building_uis_with_rsx.rs
let logged_in = use_signal(|| false);

rsx! {
    div {
        if logged_in() {
            "You are logged in"
        } else {
            "You are not logged in"
        }
    }
}
You are not logged in