# Floem: a native Rust UI library built on fine-grained reactivity

> Floem targets Rust developers who want a declarative desktop UI without a web view. The library is at v0.2.0, the README warns of occasional breaking changes, and its last push was on 2026-06-21.

**lapce/floem** — A native Rust UI library with fine-grained reactivity

- Repository: https://github.com/lapce/floem
- Website: https://lap.dev/floem/
- Stars: 4,288 · Forks: 220
- Language: Rust
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/lapce-floem

## What Floem is for, and who it is not for

Floem is a native Rust UI library. The README describes it as having fine-grained reactivity and great ergonomics, and it says the project is inspired by Xilem, Leptos and rui. The target reader is a Rust developer building a desktop application who wants a declarative view API and does not want to ship a web view to get one. The widget gallery example in the repository is the intended way to sample the library, according to the README.

The README is direct about maturity: the project is still maturing, will make occasional breaking changes, and will add missing features on the way to v1. The repository's own version is 0.2.0, and the most recent tagged release listed is v0.2.0 from 2024-11-15, with v0.1.1 before it. That release cadence is a real constraint for anyone who needs a frozen API. If you are writing a long-lived product and cannot absorb breaking changes between minor versions, this is the wrong starting point today.

## Signals, a one-time view tree, and the renderer split

The reactivity model is the core mechanism. The README says the entire library is built around reactive primitives inspired by leptos_reactive, and that signals keep the UI up to date with minimal effort. In the quickstart, a counter is an RwSignal::new(0), buttons mutate it with action closures, and a label is built with Label::derived from a closure that formats the current value. The label recomputes because it reads the signal, not because a parent re-renders a subtree.

That connects to the second design decision: the README states the view tree is constructed only once, which prevents a view generation function from becoming a bottleneck that slows the whole application. This is the opposite of immediate-mode UI, where the whole interface is rebuilt every frame. Floem also ships a virtual list example as a tool for writing efficient UI code.

Rendering is layered. The README says Floem supports Windows, macOS and Linux, rendering with wgpu via vger or vello, or via AnyRender's GPU-backed Skia renderer. When a GPU is unavailable, a CPU renderer powered by tiny-skia is used. The repository layout matches this: top-level entries include renderer, skia, vello, vger and tiny_skia as separate workspace members, alongside reactive, editor-core and ui-events-winit. Layout comes from Taffy, which the README says provides Flexbox and Grid on any View node.

## Installing Floem and running the counter example

The README does not give a cargo add line or a crate install command. What it does give is a quickstart program, and the repository is a Cargo workspace whose package is named floem. The workspace declares rust-version = 1.91 and edition 2024, so that is the toolchain floor to check before you start. The README also points to a cloud dev environment through Lapdev with dependencies pre-installed, and to the widget gallery example for a broader sample.

The quickstart below is copied from the README. It creates a signal, wires two buttons to it, and derives a label from it. After floem::launch runs, you should see a centered horizontal row with an Increment button, a value label, and a Decrement button.

```rust
use floem::prelude::*;

fn main() {
    floem::launch(counter_view);
}

fn counter_view() -> impl IntoView {
    let mut counter = RwSignal::new(0);

    Stack::horizontal((
        Button::new("Increment").action(move || counter += 1),
        Label::derived(move || format!("Value: {counter}")),
        Button::new("Decrement").action(move || counter -= 1),
    ))
    .style(|s| s.size_full().items_center().justify_center().gap(10))
}
```

To see the wider widget set rather than the counter, the README says to check out the repository and run the widget gallery example with cargo. The example lives at examples/widget-gallery/src/main.rs. The repository also carries examples for async resources, timers, localization, themes, a syntax editor and a full editor, which are the fastest way to see whether a given widget behaves the way you need.

## The inspector, theming and localization are the parts teams underestimate

Three features in the README are easy to skim past and hard to replace once you have built on them. The first is the element inspector, described as a diagnostic tool inspired by browser developer tools for debugging layout. Layout bugs in a flex and grid system are usually found by trial and error, so a tree inspector changes how quickly you can diagnose a misplaced node.

The second is theming. The README says widgets can be customized in appearance and behavior through the styling API, that styling supports theming with classes, and that third-party themes can be installed. It also mentions global light and dark themes and a built-in design system for declaring your own. Transitions and animations build on the same style system: CSS-like transitions on any interpolable property, full keyframe animations, and spring easing functions.

The third is localization, handled through the Fluent crate with fallbacks, runtime language switching, and the ability to override the active language for part of an application. That last capability is unusual and matters if you have a single panel that must render in a different language from the rest of the window. None of these are reasons to pick Floem on their own, but they are the difference between a demo and something you can ship.

## Where Floem will cost you time

The clearest limitation is stated by the project itself: breaking changes will happen before v1. A library at 0.2.0 with a release from 2024-11-15 means you should expect to read the changelog before every upgrade, and the repository does carry a CHANGELOG.md at the top level. Treat the dependency as a moving target rather than a fixed platform.

The second cost is the dependency surface. The workspace pulls in wgpu 27.0, winit pinned to a specific git revision of a lapce fork, parley and fontique for text, Taffy for layout, muda for menus, and separate renderer crates for vger, vello, skia and tiny-skia. That is a lot of native code to compile, and it is why the README offers a pre-configured Lapdev environment. If your build pipeline is sensitive to long compile times or to git dependencies, that pin on the winit fork is worth checking first.

The third is scope. The README describes Windows, macOS and Linux only. There is no web target documented, so if you need the same UI in a browser, Floem is not the tool. And if your application is a form over a database, the reactivity model and the one-time view tree are more machinery than the job needs.

## Floem against Xilem and the immediate-mode approach

The README names Xilem, Leptos and rui as inspirations, and Xilem is the closest comparison because it is also a native Rust UI library with a declarative view tree. The difference the README implies is in state: Floem builds the entire library around signals borrowed from leptos_reactive, so a widget subscribes to the state it reads. Xilem's model is centered on a view tree that is rebuilt and diffed as application state changes. Both keep the tree rather than redrawing the world each frame, but the update path differs: signal-driven recomputation in one case, tree reconciliation in the other.

The other real alternative is the immediate-mode family, where the interface is described from scratch every frame. That model is simpler to reason about and has no subscription graph to get wrong, but it re-runs your view code continuously. Floem's README explicitly frames the one-time view tree as protection against a view generation function becoming a bottleneck, which is the argument against immediate mode. If your UI is small and redraws cheaply, that protection buys you little and the signal API is extra concepts to learn.

## Conclusion

Adopt Floem if you are building a native desktop tool in Rust and you accept a pre-v1 library that the README says will make occasional breaking changes. Do not adopt it if you need a stable API surface or a web target, because the README lists only Windows, macOS and Linux. Before committing, verify that your toolchain meets the workspace rust-version of 1.91 and that the renderer path you intend to use is the one your platform supports.

## FAQ

### What is Floem in the Rust ecosystem?

Floem is a native Rust UI library with fine-grained reactivity, described in its README as inspired by Xilem, Leptos and rui. It renders through wgpu, Skia via AnyRender, or a tiny-skia CPU fallback, and uses Taffy for Flexbox and Grid layout.

### What Rust version does Floem require?

The workspace Cargo.toml sets rust-version = 1.91 and edition 2024, so that is the toolchain floor for building the library and its workspace members.

### Is the Floem API stable enough for production?

The README states the project is still maturing and will make occasional breaking changes and add missing features on the way to v1. The workspace version is 0.2.0 and the most recent tagged release is v0.2.0 from 2024-11-15.

### Which platforms does Floem support?

The README says Floem supports Windows, macOS and Linux. Rendering uses wgpu via vger or vello, or AnyRender's GPU-backed Skia renderer, with a CPU renderer powered by tiny-skia when a GPU is unavailable.

## Sources

- [lapce/floem on GitHub](https://github.com/lapce/floem)
- [License: MIT](https://github.com/lapce/floem/blob/main/LICENSE)
- [Project website](https://lap.dev/floem/)
- [README](https://github.com/lapce/floem/blob/main/README.md)
- [Releases](https://github.com/lapce/floem/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lapce-floem
