Please note: This framework is in active development. I'm keeping it in a cycle of 0.0.x releases at the moment to indicate that it’s not even ready for its 0.1.0. Active work is being done on documentation and features, and APIs should not necessarily be considered stable. At the same time, it is more than a toy project or proof of concept, and I am actively using it for my own application development.
```rust use leptos::*;
pub fn SimpleCounter(cx: Scope, initialvalue: i32) -> Element { // create a reactive signal with the initial value let (value, setvalue) = createsignal(cx, initialvalue);
// create event handlers for our buttons
// note that `value` and `set_value` are `Copy`, so it's super easy to move them into closures
let clear = move |_| set_value(0);
let decrement = move |_| set_value.update(|value| *value -= 1);
let increment = move |_| set_value.update(|value| *value += 1);
// this JSX is compiled to an HTML template string for performance
view! {
cx,
<div>
<button on:click=clear>"Clear"</button>
<button on:click=decrement>"-1"</button>
<span>"Value: " {move || value().to_string()} "!"</span>
<button on:click=increment>"+1"</button>
</div>
}
}
// Easy to use with Trunk (trunkrs.dev) or with a simple wasm-bindgen setup
pub fn main() {
mounttobody(|cx| view! { cx,
```
Leptos is a full-stack, isomorphic Rust web framework leveraging fine-grained reactivity to build declarative user interfaces.
Resource
s) and HTML (out-of-order streaming of <Suspense/>
components.)Here are some resources for learning more about Leptos:
On the surface level, these two libraries may seem similar. Yew is, of course, the most mature Rust library for web UI development and has a huge ecosystem. Here are some conceptual differences:
Conceptually, these two frameworks are very similar: because both are built on fine-grained reactivity, most apps will end up looking very similar between the two, and Sycamore or Leptos apps will both look a lot like SolidJS apps, in the same way that Yew or Dioxus can look a lot like React.
There are some practical differences that make a significant difference:
view
macro. Sycamore offers the choice of its own templating DSL or a builder syntax.view
macro compiles to a static HTML string and a set of instructions of how to assign its reactive values. This means that at runtime, Leptos can clone a <template>
node rather than calling document.createElement()
to create DOM nodes. This is a significantly faster way of rendering components.let (count, set_count) = create_signal(cx, 0);
count()
instead of count.get()
) This creates a more consistent mental model: accessing a reactive value is always a matter of calling a function. For example:```rust let (count, setcount) = createsignal(cx, 0); // a signal let doublecount = move || count() * 2; // a derived signal let memoizedcount = creatememo(cx, move || count() * 3); // a memo // all are accessed by calling them asserteq!(count(), 0); asserteq!(doublecount(), 0); asserteq!(memoized_count(), 0);
// this function can accept any of those signals fn doworkonsignal(mysignal: impl Fn() -> i32) { ... } ```
'static
: Both Leptos and Sycamore ease the pain of moving signals in closures (in particular, event listeners) by making them Copy
, to avoid the { let count = count.clone(); move |_| ... }
that's very familiar in Rust UI code. Sycamore does this by using bump allocation to tie the lifetimes of its signals to its scopes: since references are Copy
, &'a Signal<T>
can be moved into a closure. Leptos does this by using arena allocation and passing around indices: types like ReadSignal<T>
, WriteSignal<T>
, and Memo<T>
are actually wrapper for indices into an arena. This means that both scopes and signals are both Copy
and 'static
in Leptos, which means that they can be moved easily into closures without adding lifetime complexity.