{"id":15289050,"url":"https://github.com/satelllte/tailwind-join","last_synced_at":"2025-10-07T03:30:52.071Z","repository":{"id":65748563,"uuid":"598823839","full_name":"satelllte/tailwind-join","owner":"satelllte","description":"A tiny utility to join Tailwind classes instead of placing them all into a single line.","archived":true,"fork":false,"pushed_at":"2023-05-01T08:59:43.000Z","size":386,"stargazers_count":3,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-09T17:13:24.256Z","etag":null,"topics":["classnames","clsx","tailwind-css","tailwind-join","tailwind-merge","tailwindcss","tailwindcss-plugin","tw-join"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/tailwind-join","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/satelllte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-07T21:56:02.000Z","updated_at":"2023-07-10T10:00:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"a20ad085-f8b3-49f4-82e6-47b924e2c62b","html_url":"https://github.com/satelllte/tailwind-join","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/satelllte/tailwind-join","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satelllte%2Ftailwind-join","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satelllte%2Ftailwind-join/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satelllte%2Ftailwind-join/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satelllte%2Ftailwind-join/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/satelllte","download_url":"https://codeload.github.com/satelllte/tailwind-join/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satelllte%2Ftailwind-join/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278715508,"owners_count":26033296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["classnames","clsx","tailwind-css","tailwind-join","tailwind-merge","tailwindcss","tailwindcss-plugin","tw-join"],"created_at":"2024-09-30T15:58:39.415Z","updated_at":"2025-10-07T03:30:52.066Z","avatar_url":"https://github.com/satelllte.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tailwind-join\n\nA tiny utility to join [Tailwind](https://tailwindcss.com/) classes instead of placing them all into a single line.\n\n```ts\nimport { twJoin } from 'tailwind-join'\n\ntwJoin(\n  'm-4',\n  'px-2 py-1',\n  'bg-red-700 hover:bg-red-500',\n) // -\u003e 'm-4 px-2 py-1 bg-red-700 hover:bg-red-500'\n```\n\n## Install\n\n```bash\nnpm i tailwind-join\n```\n\n## Features\n\n### Split classes into multiple lines:\n\n```ts\ntwJoin(\n  'm-4',                          // spacing\n  'border border-red-400',        // borders\n  'bg-red-700 hover:bg-red-500',  // colors\n) // -\u003e 'm-4 border border-red-400 bg-red-700 hover:bg-red-500'\n```\n\n### Show \u0026 hide classes conditionally:\n\n```ts\ntwJoin(\n  isLarge ? 'm-4' : 'm-2',  // ternary\n  isRed \u0026\u0026 'bg-red',        // logical conjunction\n)\n```\n\n### Also:\n\n- Bundle size is very tiny (less than 300 bytes minified \u0026 gzipped). Check out [\"tailwind-join\" on Bundlephobia](https://bundlephobia.com/package/tailwind-join).\n- TypeScript support.\n- Works in all modern browsers and Node.js@16+.\n\n## FAQ\n\n### What is the difference between `tailwind-join` and other utilities like [classnames](https://www.npmjs.com/package/classnames), [clsx](https://www.npmjs.com/package/clsx)?\n\n`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.\n\n### Why not just use multiple lines for classes?\n\nYou 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:\n\n```html\n\u003cdiv class=\"m-4 px-2 py-1 bg-black\"\u003e\n  ...\n\u003c/div\u003e\n```\n\n### Can `tailwind-join` be used for non-Tailwind classes?\n\nAbsolutely! `tailwind-join` doesn't know anything about Tailwind, it only solves the \"single line classes\" issue.\n\n### Is there any plans to expand the API of `tailwind-join`?\n\nNo. 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.\n\n### Can [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) VSCode plugin be used with `tailwind-join`?\n\nYes! Just add this to `.vscode/settings.json`:\n\n```json\n{\n  \"tailwindCSS.experimental.classRegex\": [\n    [\"twJoin\\\\(([^)]*)\\\\)\", \"'([^']*)'\"]\n  ]\n}\n```\n\n## Benchmarks\n\n### TL;DR\n\nFaster than `clsx` for the most of practical scenarios.\n\n### Details\n\nSince this utility does less job than `clsx` (no mess around with array \u0026 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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) operator to accept arguments instead of using ES5 function's `arguments` object), it does better on 2 or more arguments.\n\nHere's the benchmark example taken on Linux machine with Node.js v18:\n\n```bash\nbenchmarking: clsx (one class)\n\twarmup... 82.65ms (10 runs)\n\ttotal: 79.17ms, runs: 10 (@ 1000000 calls/iter)\n\tmean: 7.92ms, median: 7.70ms, range: [7.70..9.64]\n\tq1: 7.70ms, q3: 7.81ms\n\tsd: 7.27%\nbenchmarking: twJoin (one class)\n\twarmup... 144.26ms (10 runs)\n\ttotal: 142.09ms, runs: 10 (@ 1000000 calls/iter)\n\tmean: 14.21ms, median: 14.09ms, range: [14.07..15.30]\n\tq1: 14.09ms, q3: 14.10ms\n\tsd: 2.56%\nFastest: \"clsx (one class)\"\n---\nbenchmarking: clsx (two classes)\n\twarmup... 507.90ms (10 runs)\n\ttotal: 502.84ms, runs: 10 (@ 1000000 calls/iter)\n\tmean: 50.28ms, median: 50.26ms, range: [50.15..50.55]\n\tq1: 50.20ms, q3: 50.40ms\n\tsd: 0.24%\nbenchmarking: twJoin (two classes)\n\twarmup... 461.69ms (10 runs)\n\ttotal: 456.70ms, runs: 10 (@ 1000000 calls/iter)\n\tmean: 45.67ms, median: 45.67ms, range: [45.52..45.86]\n\tq1: 45.61ms, q3: 45.78ms\n\tsd: 0.22%\nFastest: \"twJoin (two classes)\"\n---\nbenchmarking: clsx (many classes)\n\twarmup... 968.78ms (10 runs)\n\ttotal: 915.21ms, runs: 10 (@ 1000000 calls/iter)\n\tmean: 91.52ms, median: 91.46ms, range: [91.34..91.89]\n\tq1: 91.43ms, q3: 91.67ms\n\tsd: 0.18%\nbenchmarking: twJoin (many classes)\n\twarmup... 784.45ms (10 runs)\n\ttotal: 783.18ms, runs: 10 (@ 1000000 calls/iter)\n\tmean: 78.32ms, median: 78.32ms, range: [78.20..78.53]\n\tq1: 78.25ms, q3: 78.46ms\n\tsd: 0.14%\nFastest: \"twJoin (many classes)\"\n```\n\nFor more benchmark runs see: https://github.com/satelllte/tailwind-join/actions/workflows/benchmark.yml\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsatelllte%2Ftailwind-join","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsatelllte%2Ftailwind-join","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsatelllte%2Ftailwind-join/lists"}