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:
rsx! { "Hello world" }
You can include formatted segments inside of the text just like the format!
macro:
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}" }
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:
rsx! { input {} }
Bonus: web components
src/building_uis_with_rsx.rsrsx! { 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:
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:
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:
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:
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:
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:
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:
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:
let logged_in = use_signal(|| false); rsx! { div { if logged_in() { "You are logged in" } else { "You are not logged in" } } }