Skip to main content

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.

Conditional rendering allows you to display different content based on your application’s state. Dioxus provides several patterns for conditional rendering.

If/Else in RSX

Basic If/Else

Use standard Rust if/else expressions directly in RSX:
use dioxus::prelude::*;

fn app() -> Element {
    let mut is_logged_in = use_signal(|| false);
    
    rsx! {
        if is_logged_in() {
            h1 { "Welcome back!" }
        } else {
            h1 { "Please log in" }
        }
    }
}

If/Else with Elements

Both branches must return the same type (Element):
fn app() -> Element {
    let mut has_data = use_signal(|| true);
    
    rsx! {
        div {
            if has_data() {
                div { class: "content",
                    h2 { "Data Loaded" }
                    p { "Here is your data" }
                }
            } else {
                div { class: "loading",
                    p { "Loading..." }
                }
            }
        }
    }
}

Unterminated If Statements

Optional Rendering

For rendering something or nothing, use an unterminated if:
fn app() -> Element {
    let mut show_message = use_signal(|| true);
    
    rsx! {
        div {
            h1 { "My App" }
            
            // Only render if condition is true
            if show_message() {
                div { class: "alert",
                    "This is an important message!"
                }
            }
            
            button {
                onclick: move |_| show_message.toggle(),
                "Toggle Message"
            }
        }
    }
}

Multiple Conditions

Chain multiple unterminated if statements:
fn app() -> Element {
    let mut count = use_signal(|| 0);
    
    rsx! {
        div {
            h1 { "Count: {count}" }
            
            if count() > 10 {
                p { class: "warning", "Count is getting high!" }
            }
            
            if count() > 20 {
                p { class: "error", "Count is too high!" }
            }
            
            if count() == 0 {
                p { "Click the button to start counting" }
            }
            
            button {
                onclick: move |_| count += 1,
                "Increment"
            }
        }
    }
}

Match Expressions

Matching on Enums

#[derive(Clone, PartialEq)]
enum PageState {
    Loading,
    Success(String),
    Error(String),
}

fn app() -> Element {
    let state = use_signal(|| PageState::Loading);
    
    rsx! {
        div {
            match state() {
                PageState::Loading => rsx! {
                    div { class: "spinner", "Loading..." }
                },
                PageState::Success(data) => rsx! {
                    div { class: "content",
                        h1 { "Success!" }
                        p { "{data}" }
                    }
                },
                PageState::Error(error) => rsx! {
                    div { class: "error",
                        h1 { "Error" }
                        p { "{error}" }
                    }
                }
            }
        }
    }
}

Matching on Values

fn app() -> Element {
    let mut status = use_signal(|| 1);
    
    rsx! {
        div {
            match status() {
                0 => rsx! { p { "Inactive" } },
                1 => rsx! { p { "Active" } },
                2 => rsx! { p { "Pending" } },
                _ => rsx! { p { "Unknown" } },
            }
        }
    }
}

Working with Options

Rendering Optional Values

fn app() -> Element {
    let mut user_name = use_signal(|| None::<String>);
    
    rsx! {
        div {
            if let Some(name) = user_name() {
                h1 { "Hello, {name}!" }
            } else {
                h1 { "Hello, Guest!" }
            }
            
            button {
                onclick: move |_| user_name.set(Some("Alice".to_string())),
                "Log In"
            }
        }
    }
}

Using Option Methods

fn app() -> Element {
    let mut data = use_signal(|| Some("Hello".to_string()));
    
    rsx! {
        div {
            // Render the Option directly (Some renders the value, None renders nothing)
            {data().map(|text| rsx! { p { "{text}" } })}
            
            // Or use if let
            if let Some(text) = data() {
                p { "Data: {text}" }
            }
        }
    }
}

Unwrapping with Default

fn app() -> Element {
    let mut count = use_signal(|| None::<i32>);
    
    rsx! {
        div {
            p { "Count: {count().unwrap_or(0)}" }
            
            button {
                onclick: move |_| count.set(Some(count().unwrap_or(0) + 1)),
                "Increment"
            }
        }
    }
}

Boolean Expressions

Using .then() and .then_some()

fn app() -> Element {
    let mut show = use_signal(|| true);
    
    rsx! {
        div {
            // Using .then() with a closure
            {show().then(|| rsx! { p { "Visible!" } })}
            
            // Using .then_some() with a value
            {show().then_some(rsx! { p { "Also visible!" } })}
        }
    }
}

Short-Circuit Evaluation

fn app() -> Element {
    let mut is_admin = use_signal(|| false);
    let mut is_logged_in = use_signal(|| true);
    
    rsx! {
        div {
            // Both conditions must be true
            if is_logged_in() && is_admin() {
                div { "Admin Panel" }
            }
            
            // Either condition can be true
            if is_logged_in() || is_admin() {
                div { "Welcome" }
            }
        }
    }
}

Conditional Attributes

Conditional Classes

fn app() -> Element {
    let mut is_active = use_signal(|| false);
    let mut has_error = use_signal(|| false);
    
    rsx! {
        div {
            class: "button",
            class: if is_active() { "active" },
            class: if has_error() { "error" },
            
            onclick: move |_| is_active.toggle(),
            "Toggle"
        }
    }
}

Conditional Styles

fn app() -> Element {
    let mut is_dark = use_signal(|| false);
    
    rsx! {
        div {
            background_color: if is_dark() { "#333" } else { "#fff" },
            color: if is_dark() { "#fff" } else { "#333" },
            padding: "20px",
            
            "Theme: {if is_dark() { 'Dark' } else { 'Light' }}"
            
            button {
                onclick: move |_| is_dark.toggle(),
                "Toggle Theme"
            }
        }
    }
}

Optional Attributes

fn app() -> Element {
    let mut is_disabled = use_signal(|| false);
    
    rsx! {
        button {
            // Attribute is only set when condition is true
            disabled: if is_disabled() { true },
            "Submit"
        }
        
        // Or more simply:
        button {
            disabled: is_disabled(),
            "Submit"
        }
    }
}

Complex Conditional Logic

Nested Conditions

#[derive(Clone, PartialEq)]
enum UserRole {
    Guest,
    User,
    Admin,
}

fn app() -> Element {
    let role = use_signal(|| UserRole::Guest);
    let mut is_logged_in = use_signal(|| false);
    
    rsx! {
        div {
            if is_logged_in() {
                match role() {
                    UserRole::Admin => rsx! {
                        div { "Admin Dashboard" }
                    },
                    UserRole::User => rsx! {
                        div { "User Dashboard" }
                    },
                    UserRole::Guest => rsx! {
                        div { "Limited Access" }
                    },
                }
            } else {
                div { "Please log in" }
            }
        }
    }
}

Conditional Components

#[component]
fn AdminPanel() -> Element {
    rsx! { div { "Admin Panel" } }
}

#[component]
fn UserPanel() -> Element {
    rsx! { div { "User Panel" } }
}

fn app() -> Element {
    let mut is_admin = use_signal(|| false);
    
    rsx! {
        div {
            if is_admin() {
                AdminPanel {}
            } else {
                UserPanel {}
            }
        }
    }
}

Performance Considerations

Memoization

For expensive conditional logic, use memoization:
fn app() -> Element {
    let mut data = use_signal(|| vec![1, 2, 3, 4, 5]);
    
    // Memoize the expensive computation
    let should_show = use_memo(move || {
        data.read().iter().sum::<i32>() > 10
    });
    
    rsx! {
        div {
            if should_show() {
                p { "Sum is greater than 10" }
            }
        }
    }
}

Avoiding Re-renders

Keep conditional logic simple to avoid unnecessary re-renders:
// Good: Simple boolean check
if is_visible() {
    div { "Content" }
}

// Less ideal: Complex computation in render
if expensive_calculation() {
    div { "Content" }
}

// Better: Memoize the result
let should_show = use_memo(move || expensive_calculation());
if should_show() {
    div { "Content" }
}

Common Patterns

Loading States

fn app() -> Element {
    let mut is_loading = use_signal(|| false);
    let mut data = use_signal(|| None::<String>);
    
    rsx! {
        div {
            if is_loading() {
                div { class: "spinner", "Loading..." }
            } else if let Some(content) = data() {
                div { class: "content", "{content}" }
            } else {
                button {
                    onclick: move |_| {
                        is_loading.set(true);
                        // Load data...
                    },
                    "Load Data"
                }
            }
        }
    }
}

Error States

fn app() -> Element {
    let mut error = use_signal(|| None::<String>);
    
    rsx! {
        div {
            if let Some(err) = error() {
                div { class: "error-banner",
                    p { "Error: {err}" }
                    button {
                        onclick: move |_| error.set(None),
                        "Dismiss"
                    }
                }
            }
            
            // Rest of your UI
        }
    }
}

Toggle Patterns

fn app() -> Element {
    let mut expanded = use_signal(|| false);
    
    rsx! {
        div {
            button {
                onclick: move |_| expanded.toggle(),
                if expanded() { "Hide" } else { "Show" }
            }
            
            if expanded() {
                div { class: "expanded-content",
                    p { "This content is collapsible" }
                }
            }
        }
    }
}

Next Steps

Lists

Learn how to render dynamic lists

Signals

Master reactive state management

Build docs developers (and LLMs) love