Documentation Index
Fetch the complete documentation index at: https://mintlify.com/DioxusLabs/dioxus/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Components are the building blocks of Dioxus applications. They are functions that take props and return an Element. The #[component] macro simplifies component creation with automatic props derivation.
Component Type
pub type Component<P = ()> = fn(P) -> Element;
A component is simply a function that takes props and returns an Element.
ComponentFunction Trait
The ComponentFunction trait is implemented for functions that can act as components.
pub trait ComponentFunction<Props, Marker = ()>: Clone + 'static {
fn fn_ptr(&self) -> usize;
fn rebuild(&self, props: Props) -> Element;
}
Implementations
The trait is automatically implemented for:
- Functions that take props:
fn(Props) -> Element
- Functions with no props:
fn() -> Element
The #[component] Macro
The #[component] macro is the recommended way to define components. It automatically generates the props struct and implements required traits.
Basic Usage
use dioxus::prelude::*;
#[component]
fn Greeting(name: String) -> Element {
rsx! {
div { "Hello, {name}!" }
}
}
// Usage
fn app() -> Element {
rsx! {
Greeting { name: "World" }
}
}
With Multiple Props
#[component]
fn UserCard(
name: String,
age: u32,
email: String,
) -> Element {
rsx! {
div { class: "user-card",
h2 { "{name}" }
p { "Age: {age}" }
p { "Email: {email}" }
}
}
}
// Usage
fn app() -> Element {
rsx! {
UserCard {
name: "Alice",
age: 30,
email: "alice@example.com",
}
}
}
Optional Props
#[component]
fn Button(
text: String,
#[props(default)] disabled: bool,
#[props(default)] class: String,
) -> Element {
rsx! {
button {
class: "{class}",
disabled: disabled,
"{text}"
}
}
}
// Usage - optional props can be omitted
fn app() -> Element {
rsx! {
Button { text: "Click me" }
Button {
text: "Disabled",
disabled: true,
}
}
}
Children Prop
#[component]
fn Container(children: Element) -> Element {
rsx! {
div { class: "container",
{children}
}
}
}
// Usage
fn app() -> Element {
rsx! {
Container {
h1 { "Title" }
p { "Content" }
}
}
}
Manual Props Definition
You can also manually define props using the Props trait.
Properties Trait
pub trait Properties: Clone + Sized + 'static {
type Builder;
fn builder() -> Self::Builder;
fn memoize(&mut self, other: &Self) -> bool;
fn into_vcomponent<M: 'static>(
self,
render_fn: impl ComponentFunction<Self, M>
) -> VComponent;
}
Manual Implementation
use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
text: String,
#[props(default)]
disabled: bool,
}
fn Button(props: ButtonProps) -> Element {
rsx! {
button {
disabled: props.disabled,
"{props.text}"
}
}
}
VComponent
The internal representation of a component instance.
pub struct VComponent {
pub name: &'static str,
render_fn: usize,
props: BoxedAnyProps,
}
Methods
VComponent::new()
Creates a new component instance.
pub fn new<P, M: 'static>(
component: impl ComponentFunction<P, M>,
props: P,
fn_name: &'static str,
) -> Self
where
P: Properties + 'static
VComponent::mounted_scope_id()
Gets the ScopeId this component is mounted to.
pub fn mounted_scope_id(
&self,
dynamic_node_index: usize,
vnode: &VNode,
dom: &VirtualDom,
) -> Option<ScopeId>
Component Patterns
Stateful Components
#[component]
fn Counter(initial: i32) -> Element {
let mut count = use_signal(|| initial);
rsx! {
div {
p { "Count: {count}" }
button {
onclick: move |_| count += 1,
"Increment"
}
}
}
}
Components with Effects
#[component]
fn DataFetcher(url: String) -> Element {
let mut data = use_signal(|| None::<String>);
use_effect(move || {
spawn(async move {
let response = fetch(&url).await;
data.set(Some(response));
});
});
rsx! {
div {
match data() {
Some(d) => rsx! { p { "{d}" } },
None => rsx! { p { "Loading..." } },
}
}
}
}
Higher-Order Components
#[component]
fn WithLoading<P: PartialEq + Clone + 'static>(
is_loading: bool,
component: Component<P>,
props: P,
) -> Element {
if is_loading {
rsx! { div { "Loading..." } }
} else {
rsx! { {component(props)} }
}
}
Generic Components
use dioxus::prelude::*;
#[component]
fn List<T: std::fmt::Display + 'static>(
items: Vec<T>,
) -> Element {
rsx! {
ul {
for item in items {
li { "{item}" }
}
}
}
}
Component Lifecycle
Initialization
#[component]
fn MyComponent() -> Element {
// Runs once when component mounts
use_effect(|| {
println!("Component mounted");
});
rsx! { div { "Hello" } }
}
Cleanup
#[component]
fn MyComponent() -> Element {
use_effect(|| {
// Setup
let subscription = subscribe_to_events();
// Cleanup function
move || {
subscription.unsubscribe();
}
});
rsx! { div { "Hello" } }
}
Prop Validation
Props must implement PartialEq for memoization:
#[derive(Props, PartialEq, Clone)]
struct MyProps {
name: String,
count: i32,
}
Components re-render when props change (based on PartialEq).
Best Practices
Keep Components Small
// Good: Small, focused components
#[component]
fn Header(title: String) -> Element {
rsx! { h1 { "{title}" } }
}
#[component]
fn Footer() -> Element {
rsx! { footer { "© 2024" } }
}
#[component]
fn App() -> Element {
rsx! {
Header { title: "My App" }
main { /* content */ }
Footer {}
}
}
Use Memo for Expensive Props
#[component]
fn ExpensiveList(items: Vec<Item>) -> Element {
// Only recompute when items change
let processed = use_memo(move || {
items.iter()
.map(|item| expensive_transform(item))
.collect::<Vec<_>>()
});
rsx! {
for item in processed() {
div { "{item}" }
}
}
}
See Also