Skip to main content

Classes

Struct Classes 

Source
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

Source

pub fn builder() -> ClassesBuilder

Creates a builder for a class list.

Source

pub fn new() -> Self

Creates an empty class list.

Source

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");
Source

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).

Source

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 when true, never-active when false; no reactive subscription is installed.
  • Signal<bool> - reactive Leptos signal.
  • ReadSignal<bool> - read half of a signal(...) pair.
  • RwSignal<bool> - reactive read-write signal.
  • Memo<bool> - reactive memoized computation.
  • Any Fn() -> bool + Send + Sync + 'static closure, e.g. move || is_active.get() && !disabled.get().
Source

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.

Source

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");
Source

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");
Source

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> }
}
Source

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 Clone for Classes

Source§

fn clone(&self) -> Classes

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Classes

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Classes

Source§

fn default() -> Classes

Returns the “default value” for a type. Read more
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.

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§

fn from(entries: &[(N, C)]) -> Self

Converts to this type from the input type.
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.

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§

fn from(names: &[N]) -> Self

Converts to this type from the input type.
Source§

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§

fn from(name: &'static str) -> Self

Converts to this type from the input type.
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.

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§

fn from(entries: [(N, C); M]) -> Self

Converts to this type from the input type.
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.

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§

fn from(names: [N; M]) -> Self

Converts to this type from the input type.
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.

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§

fn from((name, when): (N, C)) -> Self

Converts to this type from the input type.
Source§

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§

fn from(name: ClassName) -> Self

Converts to this type from the input type.
Source§

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§

fn from(name: Cow<'static, str>) -> Self

Converts to this type from the input type.
Source§

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§

fn from(name: String) -> Self

Converts to this type from the input type.
Source§

impl IntoClass for Classes

Source§

type AsyncOutput = Classes

The type after all async data have resolved.
Source§

type State = ClassesState

The view state retained between building and rebuilding.
Source§

type Cloneable = Classes

An equivalent value that can be cloned.
Source§

type CloneableOwned = Classes

An equivalent value that can be cloned and is 'static.
Source§

fn html_len(&self) -> usize

The estimated length of the HTML.
Source§

fn to_html(self, class: &mut String)

Renders the class to HTML.
Source§

fn should_overwrite(&self) -> bool

Whether this class attribute should overwrite previous class values. Returns true for class="..." attributes, false for class:name=value directives.
Source§

fn hydrate<const FROM_SERVER: bool>(self, el: &Element) -> Self::State

Adds interactivity as necessary, given DOM nodes that were created from HTML that has either been rendered on the server, or cloned for a <template>.
Source§

fn build(self, el: &Element) -> Self::State

Adds this class to the element during client-side rendering.
Source§

fn rebuild(self, state: &mut Self::State)

Updates the value.
Source§

fn into_cloneable(self) -> Self::Cloneable

Converts this to a cloneable type.
Source§

fn into_cloneable_owned(self) -> Self::CloneableOwned

Converts this to a cloneable, owned type.
Source§

fn dry_resolve(&mut self)

“Runs” the attribute without other side effects. For primitive types, this is a no-op. For reactive types, this can be used to gather data about reactivity or about asynchronous data that needs to be loaded.
Source§

async fn resolve(self) -> Self::AsyncOutput

“Resolves” this into a type that is not waiting for any asynchronous data.
Source§

fn reset(state: &mut Self::State)

Reset the class list to the state before this class was added.
Source§

const TEMPLATE: &'static str = ""

The HTML that should be included in a <template>.
Source§

const MIN_LENGTH: usize = _

The minimum length of the HTML.
Source§

fn to_template(class: &mut String)

Renders the class to HTML for a <template>.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<E, T, Request, Encoding> FromReq<Patch<Encoding>, Request, E> for T
where Request: Req<E> + Send + 'static, Encoding: Decodes<T>, E: FromServerFnError,

Source§

async fn from_req(req: Request) -> Result<T, E>

Attempts to deserialize the arguments from a request.
Source§

impl<E, T, Request, Encoding> FromReq<Post<Encoding>, Request, E> for T
where Request: Req<E> + Send + 'static, Encoding: Decodes<T>, E: FromServerFnError,

Source§

async fn from_req(req: Request) -> Result<T, E>

Attempts to deserialize the arguments from a request.
Source§

impl<E, T, Request, Encoding> FromReq<Put<Encoding>, Request, E> for T
where Request: Req<E> + Send + 'static, Encoding: Decodes<T>, E: FromServerFnError,

Source§

async fn from_req(req: Request) -> Result<T, E>

Attempts to deserialize the arguments from a request.
Source§

impl<E, Encoding, Response, T> FromRes<Patch<Encoding>, Response, E> for T
where Response: ClientRes<E> + Send, Encoding: Decodes<T>, E: FromServerFnError,

Source§

async fn from_res(res: Response) -> Result<T, E>

Attempts to deserialize the outputs from a response.
Source§

impl<E, Encoding, Response, T> FromRes<Post<Encoding>, Response, E> for T
where Response: ClientRes<E> + Send, Encoding: Decodes<T>, E: FromServerFnError,

Source§

async fn from_res(res: Response) -> Result<T, E>

Attempts to deserialize the outputs from a response.
Source§

impl<E, Encoding, Response, T> FromRes<Put<Encoding>, Response, E> for T
where Response: ClientRes<E> + Send, Encoding: Decodes<T>, E: FromServerFnError,

Source§

async fn from_res(res: Response) -> Result<T, E>

Attempts to deserialize the outputs from a response.
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<E, T, Encoding, Request> IntoReq<Patch<Encoding>, Request, E> for T
where Request: ClientReq<E>, Encoding: Encodes<T>, E: FromServerFnError,

Source§

fn into_req(self, path: &str, accepts: &str) -> Result<Request, E>

Attempts to serialize the arguments into an HTTP request.
Source§

impl<E, T, Encoding, Request> IntoReq<Post<Encoding>, Request, E> for T
where Request: ClientReq<E>, Encoding: Encodes<T>, E: FromServerFnError,

Source§

fn into_req(self, path: &str, accepts: &str) -> Result<Request, E>

Attempts to serialize the arguments into an HTTP request.
Source§

impl<E, T, Encoding, Request> IntoReq<Put<Encoding>, Request, E> for T
where Request: ClientReq<E>, Encoding: Encodes<T>, E: FromServerFnError,

Source§

fn into_req(self, path: &str, accepts: &str) -> Result<Request, E>

Attempts to serialize the arguments into an HTTP request.
Source§

impl<E, Response, Encoding, T> IntoRes<Patch<Encoding>, Response, E> for T
where Response: TryRes<E>, Encoding: Encodes<T>, E: FromServerFnError + Send, T: Send,

Source§

async fn into_res(self) -> Result<Response, E>

Attempts to serialize the output into an HTTP response.
Source§

impl<E, Response, Encoding, T> IntoRes<Post<Encoding>, Response, E> for T
where Response: TryRes<E>, Encoding: Encodes<T>, E: FromServerFnError + Send, T: Send,

Source§

async fn into_res(self) -> Result<Response, E>

Attempts to serialize the output into an HTTP response.
Source§

impl<E, Response, Encoding, T> IntoRes<Put<Encoding>, Response, E> for T
where Response: TryRes<E>, Encoding: Encodes<T>, E: FromServerFnError + Send, T: Send,

Source§

async fn into_res(self) -> Result<Response, E>

Attempts to serialize the output into an HTTP response.
Source§

impl<T> SerializableKey for T

Source§

fn ser_key(&self) -> String

Serializes the key to a unique string. Read more
Source§

impl<T> StorageAccess<T> for T

Source§

fn as_borrowed(&self) -> &T

Borrows the value.
Source§

fn into_taken(self) -> T

Takes the value.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more