Skip to main content

Overview

Scopes represent individual component instances in the virtual DOM tree. Each component has its own scope that provides context, state management, and lifecycle control.

ScopeId

A unique identifier for a component scope.
pub struct ScopeId(pub usize);

Constants

ScopeId::APP
ScopeId
The ID of the user’s root scope. This scope lasts for the entire app lifetime, making it convenient for long-lived state.
// Create a signal in the app scope
let global_state = Signal::new_in_scope(
    String::new(),
    ScopeId::APP
);
ScopeId::ROOT
ScopeId
The ID of the topmost scope in the tree. This is higher than APP because Dioxus inserts default error and suspense boundaries.
ScopeId::ROOT_ERROR_BOUNDARY
ScopeId
The ID of the topmost error boundary in the tree.
ScopeId::ROOT_SUSPENSE_BOUNDARY
ScopeId
The ID of the topmost suspense boundary in the tree.

Example Usage

use dioxus::prelude::*;

#[component]
fn MyComponent() -> Element {
    // Get the current scope ID
    let scope_id = current_scope_id().unwrap();
    
    // Create state in a specific scope
    let app_state = Signal::new_in_scope(0, ScopeId::APP);
    
    rsx! {
        div { "Scope ID: {scope_id:?}" }
    }
}

ScopeState

Represents a component’s rendered state and provides access to the component’s runtime context.
pub struct ScopeState {
    runtime: Rc<Runtime>,
    context_id: ScopeId,
    last_rendered_node: Option<LastRenderedNode>,
    props: BoxedAnyProps,
    reactive_context: ReactiveContext,
}

Methods

root_node()

Gets the currently active root node for this scope.
pub fn root_node(&self) -> &VNode
Panics if the tree hasn’t been built yet.
let scope = dom.get_scope(scope_id).unwrap();
let node = scope.root_node();

try_root_node()

Tries to get the root node, returning None if not built yet.
pub fn try_root_node(&self) -> Option<&VNode>
if let Some(node) = scope.try_root_node() {
    // Process node
}

id()

Returns the scope’s ID.
pub fn id(&self) -> ScopeId
let scope = dom.get_scope(scope_id).unwrap();
let id = scope.id();

height()

Returns the scope’s height in the component tree.
pub fn height(&self) -> u32
The root scope has height 0, its children have height 1, etc.
let height = scope.height();
println!("Scope depth: {}", height);

Context API

Scopes provide context for sharing state down the component tree without prop drilling.

Providing Context

use dioxus::prelude::*;

#[derive(Clone)]
struct Theme {
    primary_color: String,
    font_size: u32,
}

#[component]
fn App() -> Element {
    // Provide context for child components
    provide_context(Theme {
        primary_color: "#007bff".to_string(),
        font_size: 16,
    });
    
    rsx! {
        ThemedButton { text: "Click me" }
    }
}

Consuming Context

#[component]
fn ThemedButton(text: String) -> Element {
    // Consume context from parent
    let theme = consume_context::<Theme>();
    
    rsx! {
        button {
            style: "color: {theme.primary_color}; font-size: {theme.font_size}px",
            "{text}"
        }
    }
}

Context Functions

provide_context
fn
Provides a context value to child components.
pub fn provide_context<T: Clone + 'static>(value: T)
consume_context
fn
Consumes a context value from parent components. Panics if not found.
pub fn consume_context<T: Clone + 'static>() -> T
try_consume_context
fn
Tries to consume a context value, returning None if not found.
pub fn try_consume_context<T: Clone + 'static>() -> Option<T>
has_context
fn
Checks if a context value exists in parent scopes.
pub fn has_context<T: 'static>() -> bool

Scope Utilities

Getting Current Scope

use dioxus::prelude::*;

#[component]
fn MyComponent() -> Element {
    let scope_id = current_scope_id().unwrap();
    
    rsx! {
        div { "Current scope: {scope_id:?}" }
    }
}

Parent Scope

use dioxus::prelude::*;

#[component]
fn ChildComponent() -> Element {
    let parent = parent_scope();
    
    rsx! {
        div { "Parent scope: {parent:?}" }
    }
}

Owner Context

use dioxus::prelude::*;

#[component]
fn MyComponent() -> Element {
    let owner = current_owner();
    
    // Run code in a specific owner context
    with_owner(owner, || {
        // This code runs with the owner context
    });
    
    rsx! { div { "Hello" } }
}

Scheduling Updates

Manual Re-renders

use dioxus::prelude::*;

#[component]
fn MyComponent() -> Element {
    // Schedule this component to re-render
    schedule_update();
    
    rsx! { div { "Will re-render" } }
}

Schedule Any Scope

// Schedule a specific scope to re-render
schedule_update_any(scope_id);

Lifecycle Hooks

Before Render

use dioxus::prelude::*;

#[component]
fn MyComponent() -> Element {
    use_before_render(move || {
        println!("About to render");
    });
    
    rsx! { div { "Hello" } }
}

After Render

#[component]
fn MyComponent() -> Element {
    use_after_render(move || {
        println!("Finished rendering");
    });
    
    rsx! { div { "Hello" } }
}

On Drop

#[component]
fn MyComponent() -> Element {
    use_drop(move || {
        println!("Component unmounting");
    });
    
    rsx! { div { "Hello" } }
}

Reactive Context

The reactive context tracks signal subscriptions for automatic re-renders.
#[component]
fn Counter() -> Element {
    let mut count = use_signal(|| 0);
    
    // Reading count subscribes this scope to updates
    let current = count();
    
    rsx! {
        div {
            p { "Count: {current}" }
            button {
                // Writing to count triggers re-render
                onclick: move |_| count += 1,
                "Increment"
            }
        }
    }
}

Scope Hierarchy

// Root Scope (ScopeId::ROOT)
//   ├─ Suspense Boundary (ScopeId::ROOT_SUSPENSE_BOUNDARY)
//   │   └─ Error Boundary (ScopeId::ROOT_ERROR_BOUNDARY)
//   │       └─ App Component (ScopeId::APP)
//   │           ├─ Child Component (ScopeId(4))
//   │           └─ Child Component (ScopeId(5))

Traversing the Tree

use dioxus::prelude::*;

fn print_scope_tree(dom: &VirtualDom, scope_id: ScopeId, depth: usize) {
    let scope = dom.get_scope(scope_id).unwrap();
    let indent = "  ".repeat(depth);
    println!("{}{:?} (height: {})", indent, scope_id, scope.height());
}

Advanced Usage

Custom Scope Storage

use dioxus::prelude::*;

#[derive(Clone)]
struct ScopeData {
    created_at: std::time::Instant,
}

#[component]
fn MyComponent() -> Element {
    // Store custom data in scope context
    provide_context(ScopeData {
        created_at: std::time::Instant::now(),
    });
    
    rsx! { div { "Component initialized" } }
}

Accessing VirtualDom from Scope

// In custom renderers or advanced use cases
let scope = dom.get_scope(scope_id).unwrap();
let root_node = scope.root_node();

// Traverse the rendered tree
for root in &root_node.template.roots {
    // Process template nodes
}

See Also

Build docs developers (and LLMs) love