#proc-macro #html #syntax #jsx

macro momenta-macros

Procedural macros for momenta, providing JSX-like syntax for Rust

4 releases

Uses new Rust 2024

0.2.3 Oct 4, 2025
0.2.2 Oct 4, 2025
0.2.1 Jul 20, 2025
0.2.0 Jun 6, 2025

#2706 in Procedural macros

Download history 111/week @ 2025-07-15 27/week @ 2025-07-22 3/week @ 2025-07-29 3/week @ 2025-08-19 1/week @ 2025-08-26 4/week @ 2025-09-02 1/week @ 2025-09-09 265/week @ 2025-09-30 37/week @ 2025-10-07 44/week @ 2025-10-14 21/week @ 2025-10-21 3/week @ 2025-10-28

145 downloads per month
Used in 5 crates (3 directly)

MIT license

45KB
813 lines

Momenta

Simple and performant reactivity for building user interfaces

A fine-grained reactive framework for Rust that makes it simple to build high-performance, reactive user interfaces using Rust's type system and ownership model.

Crates.io Documentation License Coverage Status

use momenta::prelude::*;

#[component]
fn Counter() -> Node {
    let count = create_signal(0);
    
    rsx! {
        <div class="counter">
            <h1>"Count: " {count}</h1>
            <button on:click={move |_| count += 1}>"Increment"</button>
        </div>
    }
}

Features

Element-Level Reactivity

Fine-grained reactivity that automatically tracks dependencies and updates only what has changed.

Type-Safe Components

Leverage Rust's type system for compile-time guarantees and better developer experience.

Lightweight & Fast

Small runtime with minimal overhead. Your apps stay fast and bundle sizes stay small.

Familiar API

Inspired by React with a Rust-first approach to reactive programming.

SSR Ready

Server-side rendering support out of the box with a simple API for better performance and SEO.

Composable Primitives

Build complex UIs from simple, reusable reactive primitives:

  • Signals - Fine-grained reactive state
  • Computed Signals - Derived values with automatic memoization
  • Effects - Side effect management
  • Resources - Async data loading with built-in loading/error states

Quick Start

Add Momenta to your Cargo.toml:

[dependencies]
momenta = "0.2"

Create your first component:

use momenta::prelude::*;

#[component]
fn App() -> Node {
    let count = create_signal(0);
    
    rsx! {
        <div>
            <h1>"Counter: " {count}</h1>
            <button on:click={move |_| count += 1}>
                "Increment"
            </button>
            <button on:click={move |_| count -= 1}>
                "Decrement"
            </button>
        </div>
    }
}

fn main() {
    momenta::dom::render_root::<App>("#app");
}

Why Momenta?

I started this project while attempting to transit my portfolio from Next.js to Rust. I tried using dioxus, yew, and hypertext, but I found them to be too complex and verbose for my needs. I wanted a simple and intuitive way to write HTML-like templates in Rust, while still leveraging the full power of Rust's type system.

Momenta aims to provide:

  • Simplicity - Easy to learn, easy to use
  • Performance - Fine-grained reactivity means minimal updates
  • Type Safety - Leverage Rust's type system for compile-time guarantees
  • Familiarity - React-like API that's easy to pick up

Core Concepts

Signals - Reactive State

let count = create_signal(0);
count.set(5);           // Set value
let value = count.get(); // Get value
count += 1;             // Update with operators

Computed Signals - Derived Values

let count = create_signal(0);
let doubled = create_computed(move || count.get() * 2);
// or use the derive method
let tripled = count.derive(|&n| n * 3);

Effects - Side Effects

create_effect(|| {
    console::log!("Count changed to: {}", count.get());
});

Resources - Async Data

let user = create_resource(|| async {
    fetch_user_data().await
});

rsx! {
    <div>
        {when!(user.loading() => <p>"Loading..."</p>
        else when!(user.error().is_some() => <p>"Error loading user"</p>)
        else <p>"User: " {user.get().unwrap()}</p>)}
    </div>
}

Components - Reusable UI

pub struct ButtonProps {
    pub label: &'static str,
    pub on_click: Box<dyn Fn()>,
}

#[component]
fn Button(props: &ButtonProps) -> Node {
    rsx! {
        <button on:click={move |_| (props.on_click)()}>
            {props.label}
        </button>
    }
}

Control Flow - Conditionals & Lists

// Conditional rendering
{when!(show => <p>"Visible"</p> else <p>"Hidden"</p>)}

// List rendering
let items = create_signal(vec!["Apple", "Banana", "Cherry"]);
rsx! {
    <ul>
        {items.map(|item| rsx!(<li>{item}</li>))}
    </ul>
}

Documentation

Feature Flags

Enable optional features in your Cargo.toml:

[dependencies]
momenta = { version = "0.2", features = ["full-reactivity"] }

Available features:

  • dom - All HTML elements with DOM rendering (default)
  • wasm - WebAssembly support for browser rendering (default)
  • computed - Computed signals support
  • memoization - Memoization utilities
  • full-reactivity - All reactive features (includes computed + memoization, default)

For server-side rendering without DOM, use only momenta-core:

[dependencies]
momenta-core = "0.2"

Community & Support

Contributing

We welcome contributions! Here's how you can help:

  1. Report bugs - Open an issue with a minimal reproduction
  2. Suggest features - Start a discussion about your idea
  3. Improve docs - Help us make the docs better
  4. Submit PRs - Fix bugs or implement features

Please read our Contributing Guide before submitting PRs.

Comparison with Other Frameworks

Feature Momenta Yew Dioxus
Fine-grained reactivity Yes No Yes
JSX-like syntax Yes Yes Yes
SSR Support Yes Yes Yes
Learning curve Low Medium Medium
Bundle size Small Large Medium

License

MIT License - see LICENSE for details

Dependencies

~2.1–3.5MB
~66K SLoC