Skip to content
This repository has been archived by the owner on Jul 10, 2023. It is now read-only.
/ tailwind-join Public archive

A tiny utility to join Tailwind classes instead of placing them all into a single line.

License

Notifications You must be signed in to change notification settings

satelllte/tailwind-join

Repository files navigation

tailwind-join

A tiny utility to join Tailwind classes instead of placing them all into a single line.

import { twJoin } from 'tailwind-join'

twJoin(
  'm-4',
  'px-2 py-1',
  'bg-red-700 hover:bg-red-500',
) // -> 'm-4 px-2 py-1 bg-red-700 hover:bg-red-500'

Install

npm i tailwind-join

Features

Split classes into multiple lines:

twJoin(
  'm-4',                          // spacing
  'border border-red-400',        // borders
  'bg-red-700 hover:bg-red-500',  // colors
) // -> 'm-4 border border-red-400 bg-red-700 hover:bg-red-500'

Show & hide classes conditionally:

twJoin(
  isLarge ? 'm-4' : 'm-2',  // ternary
  isRed && 'bg-red',        // logical conjunction
)

Also:

  • Bundle size is very tiny (less than 300 bytes minified & gzipped). Check out "tailwind-join" on Bundlephobia.
  • TypeScript support.
  • Works in all modern browsers and Node.js@16+.

FAQ

What is the difference between tailwind-join and other utilities like classnames, clsx?

tailwind-join just focuses more on solving the Tailwind classes "hell" issue when tens of classes are placed into a single line. On the other hand, it has even smaller bundle size than classnames and clsx so it can be also intensively used for building classes conditionally using only "ternary" and "logical conjunction" operators approaches described above.

Why not just use multiple lines for classes?

You can, but the HTML output is going to have redundant spaces and line breaks, and tailwind-join takes care of it - so the final HTML output will be always solid:

<div class="m-4 px-2 py-1 bg-black">
  ...
</div>

Can tailwind-join be used for non-Tailwind classes?

Absolutely! tailwind-join doesn't know anything about Tailwind, it only solves the "single line classes" issue.

Is there any plans to expand the API of tailwind-join?

No. The main focus is to solve the "single line classes" issue. Also, the two conditional approaches - "ternary" and "logical conjunction" are also enough. Actually, you can even consider using tailwind-join as the replacement for clsx and classnames with more strict approach for conditionals. In this case they all are going to be written in the same style, without messing around with objects, nested arrays, etc.

Can Tailwind CSS IntelliSense VSCode plugin be used with tailwind-join?

Yes! Just add this to .vscode/settings.json:

{
  "tailwindCSS.experimental.classRegex": [
    ["twJoin\\(([^)]*)\\)", "'([^']*)'"]
  ]
}

Benchmarks

TL;DR

Faster than clsx for the most of practical scenarios.

Details

Since this utility does less job than clsx (no mess around with array & object arguments), it makes sense that twJoin is faster in practice. Though it does worse with a single class argument (most probably because it just uses ES6 (...args) destruction assignment operator to accept arguments instead of using ES5 function's arguments object), it does better on 2 or more arguments.

Here's the benchmark example taken on Linux machine with Node.js v18:

benchmarking: clsx (one class)
	warmup... 82.65ms (10 runs)
	total: 79.17ms, runs: 10 (@ 1000000 calls/iter)
	mean: 7.92ms, median: 7.70ms, range: [7.70..9.64]
	q1: 7.70ms, q3: 7.81ms
	sd: 7.27%
benchmarking: twJoin (one class)
	warmup... 144.26ms (10 runs)
	total: 142.09ms, runs: 10 (@ 1000000 calls/iter)
	mean: 14.21ms, median: 14.09ms, range: [14.07..15.30]
	q1: 14.09ms, q3: 14.10ms
	sd: 2.56%
Fastest: "clsx (one class)"
---
benchmarking: clsx (two classes)
	warmup... 507.90ms (10 runs)
	total: 502.84ms, runs: 10 (@ 1000000 calls/iter)
	mean: 50.28ms, median: 50.26ms, range: [50.15..50.55]
	q1: 50.20ms, q3: 50.40ms
	sd: 0.24%
benchmarking: twJoin (two classes)
	warmup... 461.69ms (10 runs)
	total: 456.70ms, runs: 10 (@ 1000000 calls/iter)
	mean: 45.67ms, median: 45.67ms, range: [45.52..45.86]
	q1: 45.61ms, q3: 45.78ms
	sd: 0.22%
Fastest: "twJoin (two classes)"
---
benchmarking: clsx (many classes)
	warmup... 968.78ms (10 runs)
	total: 915.21ms, runs: 10 (@ 1000000 calls/iter)
	mean: 91.52ms, median: 91.46ms, range: [91.34..91.89]
	q1: 91.43ms, q3: 91.67ms
	sd: 0.18%
benchmarking: twJoin (many classes)
	warmup... 784.45ms (10 runs)
	total: 783.18ms, runs: 10 (@ 1000000 calls/iter)
	mean: 78.32ms, median: 78.32ms, range: [78.20..78.53]
	q1: 78.25ms, q3: 78.46ms
	sd: 0.14%
Fastest: "twJoin (many classes)"

For more benchmark runs see: https://github.com/satelllte/tailwind-join/actions/workflows/benchmark.yml