Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

rinch-core

Core types and traits for rinch, including elements, reactive primitives, the DOM abstraction layer, hooks, and the Component trait.

Element Types

Element

The fundamental building block enum. Note that it is minimal - shell-level constructs (windows, menus, themes) are handled at the runtime level, not as Element variants.

#![allow(unused)]
fn main() {
pub enum Element {
    /// Raw HTML content rendered by the DOM backend.
    Html(String),
    /// A fragment containing multiple children.
    Fragment(Children),
    /// A custom component implementing the Component trait.
    Component(Rc<dyn Component>, Children),
}
}

WindowProps

Configuration for a window (used at the runtime level via run_with_window_props):

#![allow(unused)]
fn main() {
pub struct WindowProps {
    pub title: String,
    pub width: u32,
    pub height: u32,
    pub x: Option<i32>,
    pub y: Option<i32>,
    pub borderless: bool,
    pub resizable: bool,
    pub transparent: bool,
    pub always_on_top: bool,
    pub visible: bool,
    pub resize_inset: Option<f32>,
}
}

DOM Abstraction Layer

The fine-grained reactive rendering system is built on three core types that abstract DOM operations away from any specific backend (desktop via Taffy/Parley/Vello, or browser-native via web_sys).

DomDocument Trait

The backend abstraction. All DOM operations go through this trait:

#![allow(unused)]
fn main() {
pub trait DomDocument {
    fn create_element(&self, tag: &str) -> NodeId;
    fn create_text(&self, content: &str) -> NodeId;
    fn set_attribute(&self, node: NodeId, name: &str, value: &str);
    fn remove_attribute(&self, node: NodeId, name: &str);
    fn set_text(&self, node: NodeId, content: &str);
    fn append_child(&self, parent: NodeId, child: NodeId);
    fn insert_before(&self, parent: NodeId, child: NodeId, reference: NodeId);
    fn remove_child(&self, parent: NodeId, child: NodeId);
    fn register_handler(&self, handler: Box<dyn Fn()>) -> HandlerId;
    // ... and more
}
}

RenderScope

Context for building DOM trees. Wraps a DomDocument and provides the API that the rsx! macro calls:

#![allow(unused)]
fn main() {
impl RenderScope {
    pub fn create_element(&mut self, tag: &str) -> NodeHandle;
    pub fn create_text(&mut self, content: &str) -> NodeHandle;
    pub fn register_handler(&mut self, handler: impl Fn() + 'static) -> HandlerId;
}
}

Component functions receive a RenderScope (injected automatically by #[component]):

#![allow(unused)]
fn main() {
#[component]
fn my_component() -> NodeHandle {
    rsx! { div { "Hello" } }
}
// Expands to: fn my_component(__scope: &mut RenderScope) -> NodeHandle { ... }
}

NodeHandle

A stable reference to a DOM node. Delegates all operations via Weak<RefCell<dyn DomDocument>>:

#![allow(unused)]
fn main() {
impl NodeHandle {
    pub fn set_attribute(&self, name: &str, value: &str);
    pub fn remove_attribute(&self, name: &str);
    pub fn set_text(&self, content: &str);
    pub fn append_child(&self, child: &NodeHandle);
    pub fn insert_before(&self, child: &NodeHandle, reference: &NodeHandle);
    pub fn remove_child(&self, child: &NodeHandle);
}
}

NodeHandles are used by Effects for surgical DOM updates:

#![allow(unused)]
fn main() {
// Signal change -> Effect runs -> NodeHandle.set_text() -> Minimal re-layout
}

Component Trait

Components implement the Component trait to render directly to DOM nodes:

#![allow(unused)]
fn main() {
pub trait Component: std::fmt::Debug + 'static {
    fn render(&self, scope: &mut RenderScope, children: &[NodeHandle]) -> NodeHandle;
}
}

Reactive Module

Signal<T>

A reactive container for mutable state. Create signals directly with Signal::new(value).

#![allow(unused)]
fn main() {
impl<T> Signal<T> {
    pub fn new(value: T) -> Self;
    pub fn set(&self, value: T);
    pub fn update(&self, f: impl FnOnce(&mut T));
    pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R;
}

impl<T: Clone> Signal<T> {
    pub fn get(&self) -> T;
}
}

Preferred usage via hooks:

#![allow(unused)]
fn main() {
#[component]
fn counter() -> NodeHandle {
    let count = Signal::new(0);
    rsx! {
        p { {|| count.get().to_string()} }
        button { onclick: move || count.update(|n| *n += 1), "+" }
    }
}
}

Effect

A side-effect that tracks signal dependencies and re-runs when they change.

#![allow(unused)]
fn main() {
impl Effect {
    pub fn new<F: FnMut() + 'static>(f: F) -> Self;
    pub fn new_deferred<F: FnMut() + 'static>(f: F) -> Self;
    pub fn run(&self);
    pub fn dispose(&self);
}
}

In practice, Effects are created automatically by the rsx! macro for reactive expressions ({|| expr}), and by Effect::new() for explicit side effects.

Memo<T>

A cached computed value that automatically re-computes when its dependencies change.

#![allow(unused)]
fn main() {
impl<T: Clone + 'static> Memo<T> {
    pub fn new<F: Fn() -> T + 'static>(f: F) -> Self;
    pub fn get(&self) -> T;
}
}

Scope

Manages the lifetime of reactive primitives.

#![allow(unused)]
fn main() {
impl Scope {
    pub fn new() -> Self;
    pub fn run<R>(&self, f: impl FnOnce() -> R) -> R;
    pub fn add_effect(&self, effect: Effect);
    pub fn dispose(&self);
}
}

Reactive Primitives

PrimitivePurpose
Signal::new(value)Reactive state container
Effect::new(closure)Side effects with auto-tracked dependencies
Memo::new(closure)Cached computed values
create_context(value)Create shared context
use_context::<T>()Access shared context (panics if missing)
try_use_context::<T>()Access shared context (returns Option)

Utility Functions

batch

Batch multiple signal updates to defer effect execution:

#![allow(unused)]
fn main() {
pub fn batch<R>(f: impl FnOnce() -> R) -> R;
}

derived

Create a memo (convenience function):

#![allow(unused)]
fn main() {
pub fn derived<T: Clone + 'static>(f: impl Fn() -> T + 'static) -> Memo<T>;
}

untracked

Read signals without tracking dependencies:

#![allow(unused)]
fn main() {
pub fn untracked<R>(f: impl FnOnce() -> R) -> R;
}

Control Flow

show_dom / Show

Reactive conditional rendering. Swaps DOM content when the condition changes:

#![allow(unused)]
fn main() {
#[component]
fn example() -> NodeHandle {
    let visible = Signal::new(true);
    rsx! {
        Show {
            when: {move || visible.get()},
            div { "Visible!" }
        }
    }
}
}

for_each_dom / For

Keyed list rendering with minimal DOM operations via LIS-based reconciliation:

#![allow(unused)]
fn main() {
#[component]
fn example() -> NodeHandle {
    let items = Signal::new(vec!["a", "b", "c"]);
    rsx! {
        For {
            each: {move || items.get().into_iter().map(|s| ForItem::new(s, s)).collect()},
            |item: &ForItem| rsx! { div { {item.downcast::<&str>().unwrap()} } }
        }
    }
}
}