leptos-classes
leptos-classes is a small utility crate for passing class names through Leptos component layers without flattening
them into a plain String too early.
It is designed for component props like #[prop(into, optional)] classes: Classes, where intermediate components can
keep extending the class list and the final element can still render it reactively with class=classes.
Why
Plain String props collapse reactivity and force every intermediate layer to re-concatenate. A typed container that
preserves conditional entries and signal bindings until the final render lets components compose without that tax.
Installation
[]
= "0.1"
Compatible with Leptos 0.8. Requires Rust 1.89 or newer.
Example
use *;
use Classes;
/// The lowest-level component renders the accumulated class list
/// onto the real element.
/// Components sitting in the middle can add their own classes.
/// Root component defines the initial classes using a builder pattern
/// or can rely on `Into` conversions (see docs).
While is_dirty is true, the save button renders with class="save-button is-dirty form-action-button button".
Concepts
A Classes value is built either by chained mutation (Classes::from("foo").add(...).add_reactive(...)) or via
Classes::builder() using the with_* API. Both shapes accept static names, reactive conditions (signals, memos,
closures), mutually exclusive toggle pairs, and merging of two independently-built values via Classes::merge. A
Classes can also be constructed through one of several From impls covering string types, slices, arrays, and
(name, condition) tuples. See the API docs for the full surface.
Each entry is a single class token. Empty, whitespace-only, or whitespace-containing names (Unicode definition, so
non-breaking spaces and other non-ASCII whitespace are rejected too) panic at construction. For unknown runtime input,
use ClassName::try_new to validate without panicking. Each token may appear in at most one entry within a Classes
value. Compose conditions instead of registering the same token twice.
Rendering Semantics
Classes implements Leptos' IntoClass trait and owns the full class="..." attribute on its target element. SSR
produces a space-separated string. The SSR-then-hydrate path reuses the server-rendered attribute without a redundant
write. Reactive updates replace the whole attribute value rather than reconciling token-by-token. Mixing class=classes
on the same element with class:foo=... directives or other third-party class mutations is not supported. External
mutations are reconciled only by a reactive update that produces a different rendered class string; re-setting a
signal to its current value is a no-op and will not flush a stomped attribute.
Fully static Classes values install no reactive effect and behave like a direct class="..." attribute.
Cargo Features
nightly(off by default): forwards toleptos/nightly. Enable this only if your project already depends on Leptos with thenightlyfeature.
Testing
just verify runs the pre-PR bundle: format check, native check, wasm32-unknown-unknown check, clippy, lib tests,
doc tests, browser test, and docs with rustdoc warnings denied. Run just for the full list of recipes.
Related Crates
leptos-styles(work in progress) is thestyle-attribute counterpart to this crate, with the same prop-drilling shape and reactiveIntoStyleintegration.
Contributing
Issues and pull requests are welcome on the GitHub repository.
License
Licensed under either of MIT License or Apache License, Version 2.0 at your option.