#string #class #flexible #utility #conditionally #constructing #tiny

clsx

A flexible class name composition utility for Rust, inspired by clsx and tailwind-merge

2 releases

new 0.1.1 Jan 18, 2025
0.1.0 Jan 18, 2025

#451 in Rust patterns

35 downloads per month

MIT license

23KB
288 lines

clsx

A tiny utility for conditionally constructing space-separated class strings in Rust,
inspired by lukeed/clsx.

Crates.io docs.rs License

A single-pass, flexible, and highly efficient library for assembling “className” strings in Rust.

Overview

  • Single pass – Minimizes allocations by appending directly to a single String.
  • Flexible – Supports:
    • Strings, numbers, booleans
    • Arrays/slices, vectors, options
    • Hash maps (HashMap<String, bool>) to mimic JS object usage
    • Tuples (bool, &str) or (bool, String) for conditional insertion
    • Closures returning something that also implements ClsxArg
  • Stable Rust – No nightly features required.
Table of Contents

Installation

Add clsx to your Cargo.toml:

[dependencies]
clsx = "0.1.0"

Then in your code:

use clsx::clsx;

Usage

use clsx::clsx;

fn main() {
    // 1) Basic strings
    let classes = clsx!("foo", "bar", "baz");
    assert_eq!(classes, "foo bar baz");

    // 2) Conditional tuples
    let is_active = true;
    let is_disabled = false;
    let classes = clsx!(
        "btn",
        (is_active, "btn-active"),
        (is_disabled, "btn-disabled")
    );
    // => "btn btn-active"
    assert_eq!(classes, "btn btn-active");

    // 3) HashMap usage
    use std::collections::HashMap;
    let mut map = HashMap::new();
    map.insert("flex".to_string(), true);
    map.insert("hidden".to_string(), false);
    let classes = clsx!(map, "base");
    assert_eq!(classes, "flex base");

    // 4) Arrays & flattening
    let classes = clsx!(
        ["hello", "world"],
        (true, "testing"),
        ["nested", "classes"]
    );
    assert_eq!(classes, "hello world testing nested classes");

    // 5) Options
    let maybe_active: Option<&str> = Some("active");
    let none_str: Option<&str> = None;
    let classes = clsx!("btn", maybe_active, none_str, "p-4");
    // => "btn active p-4"
    assert_eq!(classes, "btn active p-4");

    // 6) Numbers
    let i = 10;
    let f = 3.14;
    let classes = clsx!("start", i, f, "end");
    // => "start 10 3.14 end"
    assert_eq!(classes, "start 10 3.14 end");
}

API

clsx!(...args) -> String

Flatten and conditionally assemble space-separated classes from any combination of arguments:

Type(s) Behavior
&str, String Appends if non-empty
booleans Ignored (no classes appended)
numeric types Appended as string (10, 3.14, etc.)
arrays/slices/vectors Flatten each item (recursively)
hash maps (HashMap<String, bool>) – Only the keys whose value is true get appended
tuples (bool, &str) or (bool, String) => appended only if the bool is true
option Option<T> => appended if Some, ignored if None
closures Called, and the result is appended if it’s non-empty or meets the above criteria

Note: Any empty strings, false booleans, or “falsey” checks automatically discard the class from the output.

Advanced Usage

  • Inline if Expressions
    Instead of (bool, &str), you can inline if your_bool { "class" } else { "" }:
    let show_extra = false;
    let classes = clsx!("core", if show_extra { "extra" } else { "" }, "final");
    // => "core final"
    
  • Closures returning Option<T>:
    let maybe = || -> Option<&'static str> { Some("maybe-yes") };
    let never = || -> Option<&'static str> { None };
    let output = clsx!("start", maybe, never, "end");
    // => "start maybe-yes end"
    

Benchmarks

We don’t provide cross-browser or JS benchmarks, but this crate is quite small and uses:

  • A single pass over arguments
  • Pre-allocated String capacity (approx. 8 * number_of_arguments bytes)
  • std::fmt::Write for numeric conversions to avoid small temporary buffers

For detailed performance measurements, add your own Criterion or custom benchmarks.

Support

All stable releases of Rust (>=1.60) are supported. If you find any compatibility issues, please file an issue.

Tailwind Support

Use clsx with Tailwind CSS by simply providing the Tailwind classes. For advanced autocompletion, your IDE needs to recognize clsx!(...) usage. The standard JS/TS IntelliSense extension might not work in Rust, but you may try Tailwind Language Server or a Rust-specific extension.

  • lukeed/clsx – The original JavaScript library
  • obj-str – Smaller JS utility for object-based class composition

License

MIT © RustForWeb This library is a Rust port inspired by the original clsx by Luke Edwards.

No runtime deps