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.

Context allows you to share values down the component tree without passing props through every level. It’s ideal for sharing theme data, user authentication, or application-wide state.

Basic Usage

use dioxus::prelude::*;

#[derive(Clone, Copy, PartialEq)]
enum Theme {
    Light,
    Dark,
}

fn App() -> Element {
    // Provide context at the root
    use_context_provider(|| Signal::new(Theme::Light));
    
    rsx! {
        ThemeToggle {}
        ThemedContent {}
    }
}

#[component]
fn ThemeToggle() -> Element {
    // Consume context anywhere in the tree
    let mut theme = use_context::<Signal<Theme>>();
    
    rsx! {
        button {
            onclick: move |_| {
                theme.set(match theme() {
                    Theme::Light => Theme::Dark,
                    Theme::Dark => Theme::Light,
                });
            },
            "Toggle theme"
        }
    }
}

#[component] 
fn ThemedContent() -> Element {
    let theme = use_context::<Signal<Theme>>();
    
    rsx! {
        div {
            class: match theme() {
                Theme::Light => "light",
                Theme::Dark => "dark",
            },
            "Themed content"
        }
    }
}

Function Signatures

Providing Context

fn use_context_provider<T: Clone + 'static>(f: impl FnOnce() -> T) -> T
Provides a value to all child components. The value is created once and is immutable after creation (use interior mutability like Signal for mutable state).

Consuming Context

fn use_context<T: Clone + 'static>() -> T
Consumes context provided by a parent component. Panics if the context is not found.
fn try_use_context<T: Clone + 'static>() -> Option<T>
Tries to consume context, returning None if not found.

Context with Signals

The most common pattern is providing signals as context:
#[derive(Clone, Copy)]
struct AppState {
    count: i32,
    name: String,
}

fn App() -> Element {
    // Provide a signal as context for reactive updates
    use_context_provider(|| Signal::new(AppState {
        count: 0,
        name: "App".to_string(),
    }));
    
    rsx! {
        Counter {}
        Display {}
    }
}

#[component]
fn Counter() -> Element {
    let mut state = use_context::<Signal<AppState>>();
    
    rsx! {
        button {
            onclick: move |_| state.write().count += 1,
            "Increment"
        }
    }
}

#[component]
fn Display() -> Element {
    let state = use_context::<Signal<AppState>>();
    
    rsx! {
        "Count: {state.read().count}"
    }
}

Multiple Contexts

You can provide multiple contexts in a component:
#[derive(Clone)]
struct User {
    name: String,
}

#[derive(Clone, Copy)]
enum Theme {
    Light,
    Dark,
}

fn App() -> Element {
    use_context_provider(|| Signal::new(Theme::Light));
    use_context_provider(|| Signal::new(User {
        name: "Alice".to_string(),
    }));
    
    rsx! {
        Child {}
    }
}

#[component]
fn Child() -> Element {
    let theme = use_context::<Signal<Theme>>();
    let user = use_context::<Signal<User>>();
    
    rsx! {
        "Hello, {user.read().name}!"
        "Theme: {theme:?}"
    }
}

Context Propagation

Context propagates down the component tree:
fn Root() -> Element {
    use_context_provider(|| Signal::new("root context"));
    
    rsx! { Level1 {} }
}

#[component]
fn Level1() -> Element {
    // Can access context from Root
    let ctx = use_context::<Signal<&'static str>>();
    
    rsx! { Level2 {} }
}

#[component]
fn Level2() -> Element {
    // Can also access context from Root
    let ctx = use_context::<Signal<&'static str>>();
    
    rsx! { "{ctx}" }
}

Overriding Context

Child components can override parent context:
fn App() -> Element {
    use_context_provider(|| Signal::new("parent"));
    
    rsx! {
        Child1 {}
        Section {}
    }
}

#[component]
fn Section() -> Element {
    // Override parent context for this subtree
    use_context_provider(|| Signal::new("section"));
    
    rsx! {
        Child2 {}
    }
}

#[component]
fn Child1() -> Element {
    let ctx = use_context::<Signal<&'static str>>();
    rsx! { "{ctx}" }  // "parent"
}

#[component]
fn Child2() -> Element {
    let ctx = use_context::<Signal<&'static str>>();
    rsx! { "{ctx}" }  // "section"
}

Error Handling

Graceful Fallback

#[component]
fn OptionalTheme() -> Element {
    let theme = try_use_context::<Signal<Theme>>();
    
    let theme_class = theme
        .map(|t| match t() {
            Theme::Light => "light",
            Theme::Dark => "dark",
        })
        .unwrap_or("default");
    
    rsx! {
        div { class: "{theme_class}", "Content" }
    }
}

Custom Error Messages

fn use_theme() -> Signal<Theme> {
    try_use_context::<Signal<Theme>>()
        .expect("Theme context not found. Make sure App wraps this component.")
}

#[component]
fn ThemedButton() -> Element {
    let theme = use_theme();  // Better error message if context missing
    
    rsx! { button { "Themed button" } }
}

Common Patterns

Authentication Context

#[derive(Clone)]
struct AuthContext {
    user: Option<User>,
    token: Option<String>,
}

fn App() -> Element {
    use_context_provider(|| Signal::new(AuthContext {
        user: None,
        token: None,
    }));
    
    rsx! {
        LoginForm {}
        ProtectedContent {}
    }
}

#[component]
fn LoginForm() -> Element {
    let mut auth = use_context::<Signal<AuthContext>>();
    
    let login = move |_| {
        auth.write().user = Some(User { name: "Alice".to_string() });
        auth.write().token = Some("abc123".to_string());
    };
    
    rsx! {
        button { onclick: login, "Login" }
    }
}

#[component]
fn ProtectedContent() -> Element {
    let auth = use_context::<Signal<AuthContext>>();
    
    match auth.read().user {
        Some(ref user) => rsx! { "Welcome, {user.name}!" },
        None => rsx! { "Please login" },
    }
}

Router Context

#[derive(Clone)]
struct RouterContext {
    current_route: String,
}

fn App() -> Element {
    use_context_provider(|| Signal::new(RouterContext {
        current_route: "/".to_string(),
    }));
    
    rsx! {
        NavBar {}
        PageContent {}
    }
}

Settings Context

#[derive(Clone)]
struct Settings {
    language: String,
    notifications_enabled: bool,
    theme: Theme,
}

fn App() -> Element {
    use_context_provider(|| Signal::new(Settings {
        language: "en".to_string(),
        notifications_enabled: true,
        theme: Theme::Light,
    }));
    
    rsx! {
        SettingsPanel {}
        MainContent {}
    }
}

Context vs Props

Use Props When:

  • Data flows through 1-2 component levels
  • Relationship between parent and child is explicit
  • Component needs to be reusable with different values

Use Context When:

  • Data needs to be accessed by many components
  • Intermediate components don’t use the data (prop drilling)
  • Sharing truly global or semi-global state (theme, auth, etc.)

Performance

  • Context lookups are fast (hash map lookup)
  • Use Signal in context for reactive updates
  • Context is resolved once per component, not on every render
  • Child components only rerender if they read a signal that changed

TypeScript Equivalent

Dioxus context is similar to React Context:
// React
const ThemeContext = React.createContext("light");

// Dioxus (Rust)
use_context_provider(|| Signal::new("light"));
  • use_signal - Create reactive values for context
  • global-state - Application-wide state without context
  • stores - Fine-grained nested state management

Build docs developers (and LLMs) love