TailwindCombine

CIHex.pm

Merge Tailwind CSS classes in Elixir without style conflicts.

Inspired by the upstream JS package, tailwind-merge.

Why?

Overriding Tailwind CSS classes is unintuitive.

Due to the way the CSS Cascade works, the order of CSS styles applied on an element isn't based on the order of given classes, but the order in which CSS styles appear in CSS stylesheets. Because of that, when using Tailwind CSS classes which involve the same styles (we call them conflicting classes), the final styles are indeterminate.

<% # Is it red or green? It's hard to say. %>
<div class={["h-12 bg-red-500", "bg-green-500"]}></div>

TailwindCombine solves this problem by overriding conflicting classes and keeping everything else untouched.

<div class={TailwindCombine.merge(["h-12 bg-red-500", "bg-green-500"])}></div>
<% # equals to %>
<div class="h-12 bg-green-500"></div>

Status

Installation

Add :tailwind_combine to the list of dependencies in mix.exs:

def deps do
  [
    {:tailwind_combine, <requirement>}
  ]
end

Release instructions live in RELEASING.md.

Usage

Use the default config directly:

TailwindCombine.merge("p-2 p-4")
# "p-4"

TailwindCombine.merge(["p-2", nil, ["hover:p-2", "hover:p-4"]])
# "p-2 hover:p-4"

This is usually enough for Phoenix components and HEEx templates:

<button class={TailwindCombine.merge(["px-3 py-2", @class, @active && "bg-blue-600"])}>
  Save
</button>

Helper Module

If you want a shorter local helper, define one in your application:

defmodule DemoWeb.ClassHelper do
  use TailwindCombine
end

That gives you DemoWeb.ClassHelper.tw/1:

DemoWeb.ClassHelper.tw("text-sm text-lg")
# "text-lg"

Custom Config

You can keep the default config shape and override parts of it:

defmodule DemoWeb.ClassHelper do
  colors = TailwindCombine.Config.colors() ++ ["primary", "secondary"]
  class_groups = TailwindCombine.Config.class_groups(colors: colors)

  use TailwindCombine,
    as: :merge_class,
    config: TailwindCombine.Config.new(class_groups: class_groups)
end

DemoWeb.ClassHelper.merge_class("text-red-500 text-primary")
# "text-primary"

Prefix support is also available:

defmodule DemoWeb.Tw do
  use TailwindCombine,
    config: TailwindCombine.Config.new(prefix: "tw")
end

DemoWeb.Tw.tw("tw:p-2 tw:p-4")
# "tw:p-4"

Notes

For more detail, see the documentation.

Similar projects

License

Apache License 2.0 / MIT