Top Related Projects
Rust / Wasm framework for creating reliable and efficient web applications
Fullstack app framework for web, desktop, mobile, and more.
A Rust framework for creating web apps
A library for creating reactive web apps in Rust and WebAssembly
A cross-platform GUI library for Rust, inspired by Elm
A fast static site generator in a single binary with everything built-in. https://www.getzola.org
Quick Overview
Leptos is a full-stack web framework for Rust that allows developers to build reactive web applications. It leverages WebAssembly to run Rust code in the browser and provides a component-based architecture for creating interactive user interfaces.
Pros
- Reactive programming model for efficient UI updates
- Full-stack development with Rust on both client and server
- Strong type safety and performance benefits of Rust
- Seamless integration with existing Rust ecosystems
Cons
- Steeper learning curve for developers new to Rust
- Smaller community and ecosystem compared to more established web frameworks
- Limited browser support for WebAssembly in older versions
- Potential for larger initial bundle sizes compared to JavaScript frameworks
Code Examples
Creating a simple component:
use leptos::*;
#[component]
fn Counter(cx: Scope, initial: i32) -> impl IntoView {
let (count, set_count) = create_signal(cx, initial);
view! { cx,
<div>
<button on:click=move |_| set_count.update(|count| *count += 1)>
"Click me: " {count}
</button>
</div>
}
}
Handling user input:
use leptos::*;
#[component]
fn InputExample(cx: Scope) -> impl IntoView {
let (name, set_name) = create_signal(cx, String::new());
view! { cx,
<div>
<input
type="text"
on:input=move |ev| set_name(event_target_value(&ev))
prop:value=name
/>
<p>"Hello, " {name}</p>
</div>
}
}
Using server functions:
use leptos::*;
#[server(GetWeather, "/api")]
pub async fn get_weather(city: String) -> Result<String, ServerFnError> {
// Simulated API call
Ok(format!("The weather in {} is sunny", city))
}
#[component]
fn WeatherApp(cx: Scope) -> impl IntoView {
let (city, set_city) = create_signal(cx, String::new());
let weather = create_resource(cx, city, |city| get_weather(city));
view! { cx,
<div>
<input
type="text"
on:input=move |ev| set_city(event_target_value(&ev))
prop:value=city
/>
<Suspense fallback=move || view! { cx, <p>"Loading..."</p> }>
{move || weather.read(cx).map(|w| view! { cx, <p>{w}</p> })}
</Suspense>
</div>
}
}
Getting Started
To start using Leptos, add it to your Cargo.toml
:
[dependencies]
leptos = { version = "0.5", features = ["csr"] }
Then, create a new Leptos application:
use leptos::*;
#[component]
fn App(cx: Scope) -> impl IntoView {
view! { cx,
<h1>"Hello, Leptos!"</h1>
}
}
fn main() {
mount_to_body(|cx| view! { cx, <App/> })
}
Run your application using trunk serve
for client-side rendering or cargo leptos serve
for server-side rendering.
Competitor Comparisons
Rust / Wasm framework for creating reliable and efficient web applications
Pros of Yew
- More mature and established project with a larger community
- Extensive documentation and examples available
- Supports both WebAssembly and JavaScript compilation targets
Cons of Yew
- Steeper learning curve, especially for developers new to Rust
- Larger bundle sizes compared to Leptos
- Slower compilation times, particularly for larger projects
Code Comparison
Yew:
use yew::prelude::*;
#[function_component(App)]
fn app() -> Html {
let counter = use_state(|| 0);
let onclick = {
let counter = counter.clone();
Callback::from(move |_| counter.set(*counter + 1))
};
html! {
<div>
<button {onclick}>{ "+1" }</button>
<p>{ *counter }</p>
</div>
}
}
Leptos:
use leptos::*;
#[component]
fn App(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<div>
<button on:click=move |_| set_count.update(|count| *count += 1)>
"+1"
</button>
<p>{count}</p>
</div>
}
}
Both frameworks offer similar functionality for building reactive web applications in Rust. Yew has a more traditional React-like syntax, while Leptos uses a more concise and Rust-idiomatic approach. Leptos generally offers better performance and smaller bundle sizes, but Yew has a larger ecosystem and more resources available for learning and development.
Fullstack app framework for web, desktop, mobile, and more.
Pros of Dioxus
- More mature and feature-rich ecosystem with additional tools like Dioxus CLI and Dioxus Desktop
- Supports multiple rendering backends (DOM, SSR, Desktop, TUI)
- Offers a more familiar React-like syntax for developers transitioning from JavaScript
Cons of Dioxus
- Slightly larger bundle size compared to Leptos
- Less focus on server-side rendering and hydration compared to Leptos' built-in capabilities
- Steeper learning curve for developers new to Rust due to its more complex API
Code Comparison
Dioxus:
#[component]
fn App(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
cx.render(rsx! {
button { onclick: move |_| count += 1, "Click me: {count}" }
})
}
Leptos:
#[component]
fn App() -> impl IntoView {
let (count, set_count) = create_signal(0);
view! {
<button on:click=move |_| set_count.update(|c| *c += 1)>
"Click me: " {count}
</button>
}
}
Both frameworks offer reactive state management and declarative UI composition, but Dioxus uses a more React-like syntax with the rsx!
macro, while Leptos employs a custom view!
macro for templating.
A Rust framework for creating web apps
Pros of Seed
- More mature and established project with a larger community
- Extensive documentation and examples available
- Simpler learning curve for developers familiar with The Elm Architecture
Cons of Seed
- Less performant compared to Leptos' fine-grained reactivity system
- Limited support for server-side rendering
- Lacks built-in routing capabilities
Code Comparison
Seed example:
#[update]
fn increment(orders: &mut impl Orders<Msg>) {
model.counter += 1;
}
Leptos example:
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<button on:click=move |_| set_count.update(|count| *count += 1)>
"Click me: {count}"
</button>
}
Both Seed and Leptos are Rust frameworks for building web applications, but they differ in their approach and features. Seed follows The Elm Architecture, making it easier for developers familiar with Elm or Redux. Leptos, on the other hand, uses a fine-grained reactivity system similar to Solid.js, offering better performance and a more modern approach to state management.
While Seed has been around longer and has more community resources, Leptos is gaining popularity due to its performance benefits and support for server-side rendering. Seed's simpler architecture may be preferable for smaller projects, while Leptos' reactivity system and additional features make it more suitable for larger, complex applications.
A library for creating reactive web apps in Rust and WebAssembly
Pros of Sycamore
- Simpler API with a more straightforward learning curve
- Better performance in some scenarios due to its fine-grained reactivity system
- More flexible component model, allowing for both function and struct components
Cons of Sycamore
- Smaller ecosystem and community compared to Leptos
- Less comprehensive documentation and fewer learning resources
- Limited built-in routing capabilities
Code Comparison
Sycamore:
#[component]
fn App<G: Html>(cx: Scope) -> View<G> {
view! { cx,
div {
"Hello, Sycamore!"
}
}
}
Leptos:
#[component]
fn App() -> impl IntoView {
view! {
<div>"Hello, Leptos!"</div>
}
}
Both Sycamore and Leptos are Rust frameworks for building web applications. Sycamore offers a simpler API and potentially better performance in certain cases, while Leptos has a larger ecosystem and more comprehensive documentation. The code comparison shows that both frameworks use a similar syntax for defining components, with minor differences in the function signature and view macro usage.
A cross-platform GUI library for Rust, inspired by Elm
Pros of iced
- Native GUI toolkit with a focus on performance and minimal resource usage
- Cross-platform support for desktop applications (Windows, macOS, Linux)
- Simple and intuitive API for building user interfaces
Cons of iced
- Limited to desktop applications, not suitable for web development
- Smaller community and ecosystem compared to web-based frameworks
- Steeper learning curve for developers unfamiliar with native GUI development
Code Comparison
iced example:
use iced::{button, Button, Column, Element, Sandbox, Settings, Text};
struct Counter {
value: i32,
increment_button: button::State,
decrement_button: button::State,
}
impl Sandbox for Counter {
// ... implementation details
}
Leptos example:
use leptos::*;
#[component]
fn Counter(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
view! { cx,
<button on:click=move |_| set_count.update(|count| *count += 1)>
"Count: {count}"
</button>
}
}
While both frameworks allow for building interactive UIs, iced focuses on native desktop applications with a more traditional approach, whereas Leptos is designed for web development using a reactive model. Iced's API is more verbose and requires explicit state management, while Leptos leverages signals and a declarative syntax for a more concise implementation.
A fast static site generator in a single binary with everything built-in. https://www.getzola.org
Pros of Zola
- Static site generator, resulting in fast and secure websites
- Simple setup and configuration, ideal for content-focused sites
- Built-in themes and shortcodes for easy customization
Cons of Zola
- Limited dynamic functionality compared to Leptos
- Less flexibility for complex web applications
- Steeper learning curve for developers familiar with JavaScript frameworks
Code Comparison
Zola (content creation):
+++
title = "My First Post"
date = 2023-04-15
+++
# Welcome to my blog!
This is the content of my first post.
Leptos (component creation):
#[component]
fn MyComponent(cx: Scope) -> impl IntoView {
view! { cx,
<h1>"Welcome to my app!"</h1>
<p>"This is a Leptos component."</p>
}
}
Zola focuses on content creation and static site generation, while Leptos is geared towards building dynamic web applications with a component-based architecture. Zola is more suitable for blogs and documentation sites, whereas Leptos excels in creating interactive and reactive web applications.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Website | Book | Docs.rs | Playground | Discord
You can find a list of useful libraries and example projects at awesome-leptos
.
The main
branch is currently undergoing major changes in preparation for the 0.7 release. For a stable version, please use the v0.6.13 tag
Leptos
use leptos::*;
#[component]
pub fn SimpleCounter(initial_value: i32) -> impl IntoView {
// create a reactive signal with the initial value
let (value, set_value) = create_signal(initial_value);
// 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);
// create user interfaces with the declarative `view!` macro
view! {
<div>
<button on:click=clear>Clear</button>
<button on:click=decrement>-1</button>
// text nodes can be quoted or unquoted
<span>"Value: " {value} "!"</span>
<button on:click=increment>+1</button>
</div>
}
}
// we also support a builder syntax rather than the JSX-like `view` macro
#[component]
pub fn SimpleCounterWithBuilder(initial_value: i32) -> impl IntoView {
use leptos::html::*;
let (value, set_value) = create_signal(initial_value);
let clear = move |_| set_value(0);
let decrement = move |_| set_value.update(|value| *value -= 1);
let increment = move |_| set_value.update(|value| *value += 1);
// the `view` macro above expands to this builder syntax
div().child((
button().on(ev::click, clear).child("Clear"),
button().on(ev::click, decrement).child("-1"),
span().child(("Value: ", value, "!")),
button().on(ev::click, increment).child("+1")
))
}
// Easy to use with Trunk (trunkrs.dev) or with a simple wasm-bindgen setup
pub fn main() {
mount_to_body(|| view! {
<SimpleCounter initial_value=3 />
})
}
About the Framework
Leptos is a full-stack, isomorphic Rust web framework leveraging fine-grained reactivity to build declarative user interfaces.
What does that mean?
- Full-stack: Leptos can be used to build apps that run in the browser (client-side rendering), on the server (server-side rendering), or by rendering HTML on the server and then adding interactivity in the browser (server-side rendering with hydration). This includes support for HTTP streaming of both data (
Resource
s) and HTML (out-of-order or in-order streaming of<Suspense/>
components.) - Isomorphic: Leptos provides primitives to write isomorphic server functions, i.e., functions that can be called with the âsame shapeâ on the client or server, but only run on the server. This means you can write your server-only logic (database requests, authentication etc.) alongside the client-side components that will consume it, and call server functions as if they were running in the browser, without needing to create and maintain a separate REST or other API.
- Web: Leptos is built on the Web platform and Web standards. The router is designed to use Web fundamentals (like links and forms) and build on top of them rather than trying to replace them.
- Framework: Leptos provides most of what you need to build a modern web app: a reactive system, templating library, and a router that works on both the server and client side.
- Fine-grained reactivity: The entire framework is built from reactive primitives. This allows for extremely performant code with minimal overhead: when a reactive signalâs value changes, it can update a single text node, toggle a single class, or remove an element from the DOM without any other code running. (So, no virtual DOM overhead!)
- Declarative: Tell Leptos how you want the page to look, and let the framework tell the browser how to do it.
Learn more
Here are some resources for learning more about Leptos:
- Book (work in progress)
- Examples
- API Documentation
- Common Bugs (and how to fix them!)
nightly
Note
Most of the examples assume youâre using nightly
version of Rust and the nightly
feature of Leptos. To use nightly
Rust, you can either set your toolchain globally or on per-project basis.
To set nightly
as a default toolchain for all projects (and add the ability to compile Rust to WebAssembly, if you havenât already):
rustup toolchain install nightly
rustup default nightly
rustup target add wasm32-unknown-unknown
If you'd like to use nightly
only in your Leptos project however, add rust-toolchain.toml
file with the following content:
[toolchain]
channel = "nightly"
targets = ["wasm32-unknown-unknown"]
The nightly
feature enables the function call syntax for accessing and setting signals, as opposed to .get()
and .set()
. This leads to a consistent mental model in which accessing a reactive value of any kind (a signal, memo, or derived signal) is always represented as a function call. This is only possible with nightly Rust and the nightly
feature.
cargo-leptos
cargo-leptos
is a build tool that's designed to make it easy to build apps that run on both the client and the server, with seamless integration. The best way to get started with a real Leptos project right now is to use cargo-leptos
and our starter templates for Actix or Axum.
cargo install cargo-leptos
cargo leptos new --git https://github.com/leptos-rs/start
cd [your project name]
cargo leptos watch
Open browser to http://localhost:3000/.
FAQs
Whatâs up with the name?
Leptos (λεÏÏÏÏ) is an ancient Greek word meaning âthin, light, refined, fine-grained.â To me, a classicist and not a dog owner, it evokes the lightweight reactive system that powers the framework. I've since learned the same word is at the root of the medical term âleptospirosis,â a blood infection that affects humans and animals... My bad. No dogs were harmed in the creation of this framework.
Is it production ready?
People usually mean one of three things by this question.
- Are the APIs stable? i.e., will I have to rewrite my whole app from Leptos 0.1 to 0.2 to 0.3 to 0.4, or can I write it now and benefit from new features and updates as new versions come?
The APIs are basically settled. Weâre adding new features, but weâre very happy with where the type system and patterns have landed. I would not expect major breaking changes to your code to adapt to future releases, in terms of architecture.
- Are there bugs?
Yes, Iâm sure there are. You can see from the state of our issue tracker over time that there arenât that many bugs and theyâre usually resolved pretty quickly. But for sure, there may be moments where you encounter something that requires a fix at the framework level, which may not be immediately resolved.
- Am I a consumer or a contributor?
This may be the big one: âproduction readyâ implies a certain orientation to a library: that you can basically use it, without any special knowledge of its internals or ability to contribute. Everyone has this at some level in their stack: for example I (@gbj) donât have the capacity or knowledge to contribute to something like wasm-bindgen
at this point: I simply rely on it to work.
There are several people in the community using Leptos right now for internal apps at work, who have also become significant contributors. I think this is the right level of production use for now. There may be missing features that you need, and you may end up building them! But for internal apps, if youâre willing to build and contribute missing pieces along the way, the framework is definitely usable right now.
Can I use this for native GUI?
Sure! Obviously the view
macro is for generating DOM nodes but you can use the reactive system to drive any native GUI toolkit that uses the same kind of object-oriented, event-callback-based framework as the DOM pretty easily. The principles are the same:
- Use signals, derived signals, and memos to create your reactive system
- Create GUI widgets
- Use event listeners to update signals
- Create effects to update the UI
I've put together a very simple GTK example so you can see what I mean.
The new rendering approach being developed for 0.7 supports âuniversal rendering,â i.e., it can use any rendering library that supports a small set of 6-8 functions. (This is intended as a layer over typical retained-mode, OOP-style GUI toolkits like the DOM, GTK, etc.) That future rendering work will allow creating native UI in a way that is much more similar to the declarative approach used by the web framework.
How is this different from Yew?
Yew is the most-used library for Rust web UI development, but there are several differences between Yew and Leptos, in philosophy, approach, and performance.
-
VDOM vs. fine-grained: Yew is built on the virtual DOM (VDOM) model: state changes cause components to re-render, generating a new virtual DOM tree. Yew diffs this against the previous VDOM, and applies those patches to the actual DOM. Component functions rerun whenever state changes. Leptos takes an entirely different approach. Components run once, creating (and returning) actual DOM nodes and setting up a reactive system to update those DOM nodes.
-
Performance: This has huge performance implications: Leptos is simply much faster at both creating and updating the UI than Yew is.
-
Server integration: Yew was created in an era in which browser-rendered single-page apps (SPAs) were the dominant paradigm. While Leptos supports client-side rendering, it also focuses on integrating with the server side of your application via server functions and multiple modes of serving HTML, including out-of-order streaming.
-
How is this different from Dioxus?
Like Leptos, Dioxus is a framework for building UIs using web technologies. However, there are significant differences in approach and features.
-
VDOM vs. fine-grained: While Dioxus has a performant virtual DOM (VDOM), it still uses coarse-grained/component-scoped reactivity: changing a stateful value reruns the component function and diffs the old UI against the new one. Leptos components use a different mental model, creating (and returning) actual DOM nodes and setting up a reactive system to update those DOM nodes.
-
Web vs. desktop priorities: Dioxus uses Leptos server functions in its fullstack mode, but does not have the same
<Suspense>
-based support for things like streaming HTML rendering, or share the same focus on holistic web performance. Leptos tends to prioritize holistic web performance (streaming HTML rendering, smaller WASM binary sizes, etc.), whereas Dioxus has an unparalleled experience when building desktop apps, because your application logic runs as a native Rust binary. -
How is this different from Sycamore?
Sycamore and Leptos are both heavily influenced by SolidJS. At this point, Leptos has a larger community and ecosystem and is more actively developed. Other differences:
- Templating DSLs: Sycamore uses a custom templating language for its views, while Leptos uses a JSX-like template format.
'static
signals: One of Leptosâs main innovations was the creation ofCopy + 'static
signals, which have excellent ergonomics. Sycamore is in the process of adopting the same pattern, but this is not yet released.- Perseus vs. server functions: The Perseus metaframework provides an opinionated way to build Sycamore apps that include server functionality. Leptos instead provides primitives like server functions in the core of the framework.
Top Related Projects
Rust / Wasm framework for creating reliable and efficient web applications
Fullstack app framework for web, desktop, mobile, and more.
A Rust framework for creating web apps
A library for creating reactive web apps in Rust and WebAssembly
A cross-platform GUI library for Rust, inspired by Elm
A fast static site generator in a single binary with everything built-in. https://www.getzola.org
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot