Dioxus
4 min read
Dioxus is a modern, ergonomic, and high-performance Rust framework for building user interfaces using a Virtual DOM (like React). It supports Web, Desktop, TUI, and Mobile targets using a unified component model.

Application
A dioxus app is just a normal rust application. To get started depend on dioxus and start with this main.rs:

rust
use dioxus::prelude::*;

fn main() {
dioxus::launch(App);
}

#[component]
pub fn App() -> Element {
rsx! {
p { "Hello World!" }
}
}

Components (RSX)

Dioxus components are Rust functions that return Element and use the rsx! macro (similar to JSX). The UI is made with HTML and CSS.

rust
use dioxus::prelude::*;

#[component]
fn App() -> Element {
rsx! {
div {
h1 { "Hello, Dioxus!" }
}
}
}

You can define your own components and take values (Props):

rust

#[component]
fn MyComp(value: String, myevent: EventHandler<MouseEvent>, children: Element) -> Element {
rsx! {
button {
onclick: myevent,
title: value,
{children}
}
}
}

// Usage
#[component]
fn App() -> Element {
rsx! {
MyComp {
// Event Handler
onclick: move |_| { println!("Clicked"); },
// Value
title: "my_title",
// children
p {
"Hello World"
}
}
}
}


Event Handler

Event handling is done inline using closures:

rust
rsx!(
button {
onclick: move |_| println!("Button clicked"),
"Click me"
}
)

Each event handler receives an event struct (e.g., MouseEvent, FormEvent).

Hooks

Dioxus has a powerful hook system that allows you to manage state, side effects, and asynchronous operations in your components. With these hooks the UI gets automatically reloaded when needed.

Warning: Always call the hooks in the same order or they will not work correctly. This means no hooks in loops or conditions.

use_signal

Creates a reactive value that can be read and updated. When the value changes, the component re-renders.

rust
let count = use_signal(|| 0);
rsx! {
button { onclick: move |_| count.set(count() + 1), "Increment" }
p { "Value is {count}" }
}

use_memo

Computes a derived value that only re-evaluates when its dependencies change.

rust
let doubled = use_memo(|| count() * 2);

use_effect

Runs a side effect after the component renders. Useful for operations which should run beside the UI.

rust
use_effect(|| {
// Side effect code here
});

use_resource

Manages an asynchronous resource, such as data fetched from an API.

rust
let resource = use_resource(|| fetch_data());

use_drop

Registers a callback to be run before the component is removed. Useful for cleaning up side effects.

rust
use_drop(|| {
// Cleanup code here
});

Assets
To include assets (like CSS) in our app, you can use the asset!() macro. This macro ensures the asset will be included in the final app bundle.

rust
static MY_CSS: Asset = asset!("/assets/main.css");

fn App() -> Element {
rsx! {
document::Stylesheet { href: MY_CSS }
}
}

Routing

You can have different routes in your app using dioxus router. To use the router enable the router feature in the dioxus crate.

Define the routes:

rust
// All of our routes will be a variant of this Route enum
#[derive(Routable, PartialEq, Clone)]
enum Route {
// if the current location is "/home", render the Home component
#[route("/home")]
Home {},
// if the current location is "/blog", render the Blog component
#[route("/blog")]
Blog {},
}

fn Home() -> Element {
// HomePage...
}

fn Blog() -> Element {
// BlogPage...
}

To use the router and actually render the routes, add it to your main App component:
rust
fn App() -> Element {
rsx! {
document::Stylesheet { href: asset!("/assets/main.css") }

// Renders the current route
Router::<Route> {}
}
}

To move between routes you can either use a Link element or the navigator:

rust
// Link Element
rsx! {
Link { to: Route::Home {}, "Go home!" }
}

// Navigator
rsx! {
button {
onclick: move |_| {
let nav = navigator();
// push
nav.push(Route::Blog {});
// replace
nav.replace(Route::Home {});
// go back
nav.go_back();
// go forward
nav.go_forward();
},
"Go somewhere"
}
}