Skip to main content

Easily define conditional class attributes for HTML elements.

Project description

clsx

Easily define conditional class attributes for HTML elements.

Motivation

Defining conditional class attributes based on a state can be cumbersome and error-prone with string concatenation. clsx provides a utility function to handle this logic efficiently, bringing the popular idea from the JavaScript ecosystem to the Python ecosystem.

Installation

The package is available on PyPI and can be installed using pip.

pip install clsx

Usage

The clsx function takes any number of arguments and returns a string that can be used as the value of the class attribute of an HTML element.

from clsx import clsx

clsx()                                        # ""
clsx("")                                      # ""
clsx("foo")                                   # "foo"
clsx("foo foo")                               # "foo"
clsx("foo \n\t foo")                          # "foo"

clsx("foo", None)                             # "foo"
clsx("foo", None, "bar")                      # "foo bar"

clsx("foo", None, "bar", None)                # "foo bar"
clsx("foo", None, "bar", None, "baz")         # "foo bar baz"

clsx("foo", False)                            # ""
clsx("foo", True)                             # "foo"

clsx("foo", "bar")                            # "foo bar"
clsx("foo", "bar", "baz")                     # "foo bar baz"
clsx("foo", "bar", "baz", "qux")              # "foo bar baz qux"

clsx(["foo", "bar"])                          # "foo bar"
clsx(["foo", "bar"], ["baz", "qux"])          # "foo bar baz qux"
clsx([("foo", True), ("foo", "bar", "baz")])  # "foo bar baz"

clsx(["foo foo"], "foo", "bar")               # "foo bar"
clsx("foo", ["foo", "bar", "baz"])            # "foo bar baz"

clsx({"foo": True, "bar": False})             # "foo"
clsx({"foo": True, "bar": True})              # "foo bar"
clsx({(lambda: "foo"): True})                 # "foo"

clsx(lambda: [lambda: ("foo", True)])         # "foo"

Low-level API

The core of the implementation is the methods in the ExpressionEvaluator class. For each type of input, there is a corresponding method that evaluates the input and returns an iterator of class names. These methods are designed to be chained together to form the final iterable.

For optimal performance and memory consumption, ExpressionEvaluator consists of several generator methods that yield the class names one by one, as they are consumed. This allows the evaluation process to be done lazily, which is especially useful when dealing with large/infinite and/or nested inputs. Since the evaluation is done lazily, the both the CPU and memory usage are kept to a minimum.

from clsx.evaluation import ExpressionEvaluator

output_stream = ExpressionEvaluator.evaluate(input_stream)

Modularity

The implementation supports on-the-fly modifications of class names out of the box by its nature. For more complex use cases similar to deduplication, CSS Modules resolution or anything else, the low-level API can be extended by chaining the output iterable with other generator functions. This allows for a modular design where each step of the evaluation process can be customized and extended independently, with zero extra overhead.

For an example of how to extend the low-level API, see the deduplication section below.

Deduplication

The deduplication is always enabled when using the high-level API. However, when using the low-level API, the deduplication must be done manually. This can be achieved by using the dedup function from the clsx.contrib.itertools module, which is a generator function that deduplicates the input stream without ahead of planning or buffering. See the example below.

from clsx.contrib.itertools import dedup
from clsx.evaluation import ExpressionEvaluator

output_stream = ExpressionEvaluator.evaluate(input_stream)
deduplicated_output_stream = dedup(output_stream)

CSS Modules

The CSS Modules resolution is not supported out of the box, but can be achieved by modifying the output stream by chaining it with a custom generator function that resolves the class names. See the example below.

from clsx.abc import ClassNameIterable
from clsx.evaluation import ExpressionEvaluator

STYLES = {"foo": "Zm9v"}

def resolve_css_module_class_names(
    iterable: ClassNameIterable,
) -> ClassNameIterable:
    for class_name in iterable:
        yield STYLES.get(class_name, class_name)

output_stream = ExpressionEvaluator.evaluate(input_stream)
resolved_output_stream = resolve_css_module_class_names(output_stream)

Inspiration

This project is inspired by the popular idea implemented and widely used in the JavaScript ecosystem. The name clsx is a positive nod to the project clsx by @lukeed, which provides a similar functionality for JavaScript.

The name clsx in this project is used as a shorthand for "class expression" and it might be pronounced as "classics".

License

This project is licensed under the MIT License.

See the LICENSE file for more information.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clsx-0.1.1.tar.gz (11.3 kB view details)

Uploaded Source

Built Distribution

clsx-0.1.1-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

File details

Details for the file clsx-0.1.1.tar.gz.

File metadata

  • Download URL: clsx-0.1.1.tar.gz
  • Upload date:
  • Size: 11.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.27.0

File hashes

Hashes for clsx-0.1.1.tar.gz
Algorithm Hash digest
SHA256 99f987d5034c20565d10fec98e8c24d8fca9790ac43e56dea01102bb7f062569
MD5 103f642d71ceeffe3e50079554bca3b4
BLAKE2b-256 4f6533d43dafd5b90a0a6d4e82a41ca9820e97938c527e9b20509c3221241fb3

See more details on using hashes here.

File details

Details for the file clsx-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: clsx-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 19.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.27.0

File hashes

Hashes for clsx-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 41582770291757618c86556d9652376d4c7c02db70b5ae0d2ecb330947845f4e
MD5 e0c09277d5565be92ea695c38a5a8192
BLAKE2b-256 d3ce01f74fa59ad4ab0f71ee6d1cb764c2e0562dc773220ed59631677cf79c66

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page