Tailwind-aware class composition with a swappable merge seam (Layer 3).
classes/1 flattens nested/conditional class inputs (the same shapes HEEx accepts) into a
single deduplicated string — last occurrence wins, so a caller's @class reliably overrides
defaults. This is the zero-dependency built-in default.
For real Tailwind conflict resolution (e.g. px-2 vs px-4), point the seam at a
tailwind_merge-style library:
config :mishka_chelekom, :class_merger, {TailwindMerge, :merge, 1}The configured merger is resolved at runtime via Application.get_env/3; when unset, the
built-in dedupe/1 is used. This mirrors Pyro's approach and keeps the dependency optional.
Summary
Functions
Flattens and merges class inputs into a single class string.
Built-in default merger: collapses whitespace and removes exact duplicate tokens, keeping
the last occurrence so later (caller) classes win. Does not resolve Tailwind utility
conflicts — adopt tailwind_merge via the seam for that.
Runs the configured class merger over a space-separated class string. Defaults to
dedupe/1 (token de-duplication, last wins) when no :class_merger is configured.
Types
Functions
Flattens and merges class inputs into a single class string.
Accepts strings, nested lists, nil/false (dropped), and {condition, classes} tuples.
iex> MishkaChelekom.CSS.classes(["px-2 py-1", nil, {true, "font-bold"}, {false, "hidden"}])
"px-2 py-1 font-bold"
Built-in default merger: collapses whitespace and removes exact duplicate tokens, keeping
the last occurrence so later (caller) classes win. Does not resolve Tailwind utility
conflicts — adopt tailwind_merge via the seam for that.
Runs the configured class merger over a space-separated class string. Defaults to
dedupe/1 (token de-duplication, last wins) when no :class_merger is configured.