pub struct Classes { /* private fields */ }Expand description
Leptos component-prop-utility to drill down a list of classes.
§Duplicate Handling
Each class token may appear in at most one entry across a Classes value. Registering the
same token twice, including the case where an add / add_reactive entry’s name matches one
branch of an add_toggle, panics in both debug and release builds at the point of insertion.
Compose conditions instead: if you want "foo" to render when either of two signals is true,
write add_reactive("foo", move || a.get() || b.get()) rather than adding "foo" twice.
§Class Token Validation
Each entry must be one class token, not a whitespace-separated class string. Invalid
input (empty, whitespace-only, or containing any whitespace, by the Unicode definition)
panics in both debug and release builds at the ClassName conversion. For runtime input
you want to handle without a panic, validate via ClassName::try_new and only feed
successfully-validated tokens through the entry methods.
§Attribute Ownership
Classes represents a complete class="..." attribute value. When rendered onto an element,
it owns the full class attribute and will overwrite unmanaged class mutations on the next
managed update pass or rebuild.
§Example
use leptos::prelude::*;
use leptos_classes::Classes;
/// The lowest-level component renders the class-list onto an actual HTML element.
#[component]
fn NeedingClasses(
#[prop(into, optional)] classes: Classes,
) -> impl IntoView {
view! {
<div class=classes/>
}
}
/// Components sitting in the middle can add their own classes.
#[component]
fn ExtendingClasses(
#[prop(into, optional)] classes: Classes,
) -> impl IntoView {
view! {
<NeedingClasses classes=classes.add("additional-class")/>
}
}
/// Root component defines the initial classes using a builder pattern or can rely on `Into`
/// conversions (see docs).
#[component]
fn ProvidingClasses() -> impl IntoView {
let (show_second, _) = signal(true);
view! {
<ExtendingClasses classes="single-class"/>
<ExtendingClasses classes=Classes::builder()
.with("first")
.with_reactive("second", show_second)
.build()/>
}
}Implementations§
Source§impl Classes
impl Classes
Sourcepub fn builder() -> ClassesBuilder
pub fn builder() -> ClassesBuilder
Creates a builder for a class list.
Sourcepub fn parse(input: &str) -> Self
pub fn parse(input: &str) -> Self
Parses a whitespace-separated class string into a list of always-active entries.
Splits input on Unicode whitespace (str::split_whitespace) and creates one
always-active entry per non-empty token. Empty input or whitespace-only input produces an
empty Classes. Non-breaking spaces (U+00A0) and other non-ASCII whitespace split
tokens just like ASCII whitespace, so pasting "foo\u{00A0}bar" from a rich-text source
yields two tokens rather than one whitespace-bearing token that would then fail
validation.
Unlike Classes::from(&str), which treats its argument as a single class token (and
panics on embedded whitespace), parse is the explicit opt-in for turning a runtime
"foo bar baz" style string into multiple class entries.
Tokens are inserted with the same uniqueness rule as Classes::add: if input
contains the same token more than once (e.g. "foo foo"), the second insertion panics.
Pre-deduplicate runtime input if you cannot guarantee distinct tokens.
§Example
use assertr::prelude::*;
use leptos_classes::Classes;
let classes = Classes::parse("btn btn-primary btn-large");
assert_that!(classes.to_class_string()).is_equal_to("btn btn-primary btn-large");Sourcepub fn add(self, name: impl Into<ClassName>) -> Self
pub fn add(self, name: impl Into<ClassName>) -> Self
Adds one always-active class token.
Panics if name is empty, whitespace-only, or contains any whitespace (Unicode
definition: see char::is_whitespace), or if the token is already present in this
Classes (see Duplicate Handling).
Sourcepub fn add_reactive(
self,
name: impl Into<ClassName>,
when: impl Into<ClassCondition>,
) -> Self
pub fn add_reactive( self, name: impl Into<ClassName>, when: impl Into<ClassCondition>, ) -> Self
Adds one reactive class token, controlled by when.
Same validation policy for name as Classes::add.
§Accepted when shapes
when accepts any value that converts into the internal condition type:
bool- treated as always-active whentrue, never-active whenfalse; no reactive subscription is installed.Signal<bool>- reactive Leptos signal.ReadSignal<bool>- read half of asignal(...)pair.RwSignal<bool>- reactive read-write signal.Memo<bool>- reactive memoized computation.- Any
Fn() -> bool + Send + Sync + 'staticclosure, e.g.move || is_active.get() && !disabled.get().
Sourcepub fn add_all<I>(self, iter: I) -> Self
pub fn add_all<I>(self, iter: I) -> Self
Adds multiple always-active class tokens.
Each name is validated independently per Classes::add’s policy. Iteration
short-circuits on the first invalid or duplicate token: the panic fires from inside
the loop, so items past the offending one are never inspected.
Sourcepub fn add_parsed(self, input: &str) -> Self
pub fn add_parsed(self, input: &str) -> Self
Splits input on Unicode whitespace (str::split_whitespace) and appends each
non-empty token as an always-active class entry.
Use this when you have a runtime class string you cannot pre-tokenize. Empty input or
whitespace-only input is a no-op. Non-breaking spaces (U+00A0) and other non-ASCII
whitespace split tokens just like ASCII whitespace.
Tokens land under the same uniqueness rule as Classes::add: a token from input
that duplicates one already present on self, or that appears twice within input
itself, panics at insertion time. Pre-deduplicate runtime input if you cannot guarantee
distinct tokens.
§Example
use assertr::prelude::*;
use leptos_classes::Classes;
let classes = Classes::from("base").add_parsed(" primary large ");
assert_that!(classes.to_class_string()).is_equal_to("base primary large");Sourcepub fn add_toggle(
self,
when: impl Into<ClassCondition>,
when_true: impl Into<ClassName>,
when_false: impl Into<ClassName>,
) -> Self
pub fn add_toggle( self, when: impl Into<ClassCondition>, when_true: impl Into<ClassName>, when_false: impl Into<ClassName>, ) -> Self
Adds a pair of mutually exclusive reactive classes.
The when_true class is active when the condition is true, the when_false class
when it is false. Panics if either branch is invalid (empty, whitespace-only, or
containing any whitespace, by the Unicode definition: see char::is_whitespace), if
when_true equals when_false, or if either branch collides with a class token
already registered on this Classes (see Duplicate Handling).
See Classes::add_reactive for the list of accepted when shapes.
§Example
use leptos::prelude::*;
use leptos_classes::Classes;
let (is_active, _) = signal(true);
let classes = Classes::new()
.add_toggle(is_active, "active", "inactive");Sourcepub fn merge(self, other: Classes, strategy: MergeStrategy) -> Self
pub fn merge(self, other: Classes, strategy: MergeStrategy) -> Self
Combines another Classes value into this one, appending every entry from other and
applying strategy on token collisions.
Use merge when you receive two independently-produced Classes values (a
classes: Classes prop combined with a helper return, two hook return values, a
third-party value combined with your own) that you cannot fold into one chained
construction. When you control both producers, prefer chained add_* calls on a single
Classes.
Prefer MergeStrategy::default() (which is
UnionConditions) unless you have a specific reason to
drop or reject collisions. It is the only strategy that never panics on caller input and
never silently discards a caller-supplied condition. See MergeStrategy for per-variant
semantics, including how each strategy treats collisions that involve a toggle half
(toggle-pair structure is not preserved across any merge).
§Example
use leptos::prelude::*;
use leptos_classes::{Classes, MergeStrategy};
/// A helper that produces a self-contained `Classes`.
fn primary_button_classes() -> Classes {
Classes::from("btn").add("bg-blue-600").add("text-white")
}
/// Component receives a `Classes` prop and merges in its own internal classes.
/// `MergeStrategy::default()` (== `UnionConditions`) is the right pick here: a caller
/// passing a colliding token must not crash the component.
#[component]
fn Button(#[prop(into, optional)] classes: Classes) -> impl IntoView {
let merged = classes.merge(primary_button_classes(), MergeStrategy::default());
view! { <button class=merged>"Click me"</button> }
}Sourcepub fn to_class_string(&self) -> String
pub fn to_class_string(&self) -> String
Returns the currently active classes as a space-separated String.
If called within a reactive scope, signal reads register the surrounding scope as a
subscriber. Prefer class=classes (via IntoClass) for rendering: it reuses the
string buffer across reactive updates instead of allocating a fresh String each time.
Trait Implementations§
Source§impl<N: Clone + Into<ClassName>, C: Clone + Into<ClassCondition>> From<&[(N, C)]> for Classes
Creates a Classes from a slice of (name, condition) pairs, each added as a reactive entry.
impl<N: Clone + Into<ClassName>, C: Clone + Into<ClassCondition>> From<&[(N, C)]> for Classes
Creates a Classes from a slice of (name, condition) pairs, each added as a reactive entry.
Names are validated per Classes::add; see Classes::add_reactive for the accepted
condition shapes. Duplicate tokens within the slice also panic; see the # Duplicate Handling
section on Classes.
Both N and C must be Clone because the impl clones each element during conversion.
All five built-in Into<ClassCondition> sources (bool, Signal<bool>, ReadSignal<bool>,
RwSignal<bool>, Memo<bool>) are Clone; bare closures are not and must be placed in an
array ([(N, C); M]) instead.
§Examples
use assertr::prelude::*;
use leptos::prelude::*;
use leptos_classes::Classes;
let (is_first, _) = signal(true);
let (is_second, _) = signal(false);
let entries: &[(&'static str, ReadSignal<bool>)] =
&[("first", is_first), ("second", is_second)];
let c: Classes = entries.into();
assert_that!(c.to_class_string()).is_equal_to("first");Source§impl<N: Clone + Into<ClassName>> From<&[N]> for Classes
Creates a Classes from a slice of class tokens, each added as an always-active entry.
impl<N: Clone + Into<ClassName>> From<&[N]> for Classes
Creates a Classes from a slice of class tokens, each added as an always-active entry.
Each element is validated independently per Classes::add: any invalid token panics.
Duplicate tokens within the slice also panic; see the # Duplicate Handling section on
Classes.
N must be Clone because the impl clones each element during conversion. All four
built-in Into<ClassName> sources (&'static str, String, Cow<'static, str>,
ClassName) satisfy this.
§Examples
use assertr::prelude::*;
use leptos_classes::Classes;
let names: &[&'static str] = &["btn", "btn-primary"];
let c: Classes = names.into();
assert_that!(c.to_class_string()).is_equal_to("btn btn-primary");Source§impl From<&'static str> for Classes
Creates a Classes containing a single always-active class name from a &'static str.
impl From<&'static str> for Classes
Creates a Classes containing a single always-active class name from a &'static str.
The input is treated as one class name. Panics if the string is empty, whitespace-only,
or contains any whitespace (Unicode definition). See Classes::add for the validation
policy.
For a runtime string that may contain multiple whitespace-separated tokens, use
Classes::parse instead. For runtime input you want to handle without a panic, pre-validate
with ClassName::try_new.
§Examples
use assertr::prelude::*;
use leptos_classes::Classes;
let c: Classes = "btn-primary".into();
assert_that!(c.to_class_string()).is_equal_to("btn-primary");Source§impl<N: Into<ClassName>, C: Into<ClassCondition>, const M: usize> From<[(N, C); M]> for Classes
Creates a Classes from an array of (name, condition) pairs, each added as a reactive entry.
impl<N: Into<ClassName>, C: Into<ClassCondition>, const M: usize> From<[(N, C); M]> for Classes
Creates a Classes from an array of (name, condition) pairs, each added as a reactive entry.
Names are validated per Classes::add; see Classes::add_reactive for the accepted
condition shapes. Duplicate tokens within the array also panic; see the # Duplicate Handling
section on Classes.
§Examples
use assertr::prelude::*;
use leptos::prelude::*;
use leptos_classes::Classes;
let (is_first, _) = signal(true);
let (is_second, _) = signal(false);
let c: Classes = [("first", is_first), ("second", is_second)].into();
assert_that!(c.to_class_string()).is_equal_to("first");Source§impl<N: Into<ClassName>, const M: usize> From<[N; M]> for Classes
Creates a Classes from an array of class tokens, each added as an always-active entry.
impl<N: Into<ClassName>, const M: usize> From<[N; M]> for Classes
Creates a Classes from an array of class tokens, each added as an always-active entry.
Each element is validated independently per Classes::add: any invalid token panics.
Duplicate tokens within the array also panic; see the # Duplicate Handling section on
Classes.
§Examples
use assertr::prelude::*;
use leptos_classes::Classes;
let c: Classes = ["btn", "btn-primary", "btn-large"].into();
assert_that!(c.to_class_string()).is_equal_to("btn btn-primary btn-large");Source§impl<N: Into<ClassName>, C: Into<ClassCondition>> From<(N, C)> for Classes
Creates a Classes containing a single reactive class entry from a (name, condition) tuple.
impl<N: Into<ClassName>, C: Into<ClassCondition>> From<(N, C)> for Classes
Creates a Classes containing a single reactive class entry from a (name, condition) tuple.
name is validated per Classes::add; see Classes::add_reactive for the accepted
condition shapes.
§Examples
use assertr::prelude::*;
use leptos::prelude::*;
use leptos_classes::Classes;
let (is_active, _) = signal(true);
let c: Classes = ("active", is_active).into();
assert_that!(c.to_class_string()).is_equal_to("active");Source§impl From<ClassName> for Classes
Creates a Classes containing a single always-active entry from a pre-validated ClassName.
impl From<ClassName> for Classes
Creates a Classes containing a single always-active entry from a pre-validated ClassName.
Use this when you constructed a ClassName via ClassName::try_new (the non-panicking
constructor); the conversion itself cannot fail.
§Examples
use assertr::prelude::*;
use leptos_classes::{ClassName, Classes};
let name = ClassName::try_new("btn-primary").unwrap();
let c: Classes = name.into();
assert_that!(c.to_class_string()).is_equal_to("btn-primary");Source§impl From<Cow<'static, str>> for Classes
Creates a Classes containing a single always-active class token from a Cow<'static, str>.
impl From<Cow<'static, str>> for Classes
Creates a Classes containing a single always-active class token from a Cow<'static, str>.
Same validation as Classes::add. Useful when the caller already holds a Cow,
e.g. from a configuration lookup. Use Classes::parse for runtime input that may contain
whitespace-separated tokens.
§Examples
use std::borrow::Cow;
use assertr::prelude::*;
use leptos_classes::Classes;
let c: Classes = Cow::Borrowed("btn-primary").into();
assert_that!(c.to_class_string()).is_equal_to("btn-primary");Source§impl From<String> for Classes
Creates a Classes containing a single always-active class token from an owned String.
impl From<String> for Classes
Creates a Classes containing a single always-active class token from an owned String.
Same validation as Classes::add. Use Classes::parse for a runtime String that may
contain whitespace-separated tokens.
§Examples
use assertr::prelude::*;
use leptos_classes::Classes;
let c: Classes = String::from("btn-primary").into();
assert_that!(c.to_class_string()).is_equal_to("btn-primary");Source§impl IntoClass for Classes
impl IntoClass for Classes
Source§type AsyncOutput = Classes
type AsyncOutput = Classes
Source§type CloneableOwned = Classes
type CloneableOwned = Classes
'static.Source§fn should_overwrite(&self) -> bool
fn should_overwrite(&self) -> bool
true for class="..." attributes, false for class:name=value directives.Source§fn hydrate<const FROM_SERVER: bool>(self, el: &Element) -> Self::State
fn hydrate<const FROM_SERVER: bool>(self, el: &Element) -> Self::State
<template>.Source§fn build(self, el: &Element) -> Self::State
fn build(self, el: &Element) -> Self::State
Source§fn into_cloneable(self) -> Self::Cloneable
fn into_cloneable(self) -> Self::Cloneable
Source§fn into_cloneable_owned(self) -> Self::CloneableOwned
fn into_cloneable_owned(self) -> Self::CloneableOwned
Source§fn dry_resolve(&mut self)
fn dry_resolve(&mut self)
Source§async fn resolve(self) -> Self::AsyncOutput
async fn resolve(self) -> Self::AsyncOutput
Source§fn reset(state: &mut Self::State)
fn reset(state: &mut Self::State)
Source§const MIN_LENGTH: usize = _
const MIN_LENGTH: usize = _
Source§fn to_template(class: &mut String)
fn to_template(class: &mut String)
<template>.Auto Trait Implementations§
impl Freeze for Classes
impl RefUnwindSafe for Classes
impl Send for Classes
impl Sync for Classes
impl Unpin for Classes
impl UnsafeUnpin for Classes
impl UnwindSafe for Classes
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more