tailwind-merge

Merge Tailwind CSS classes without style conflicts

Library
npm
v3.7.0
5,692 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
86 /100 Excellent
Development Activity 92
Maintenance 100
Community 56
Maturity 56
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
90 /100 Excellent
Architecture 90
Code Quality 92
Innovation 90
Learning Curve 88

tailwind-merge is a TypeScript utility that merges strings of Tailwind CSS classes and resolves conflicts between them, so that when two classes target the same styling concern the last one specified wins instead of both being applied and silently fighting in the CSS cascade.

It ships with zero runtime dependencies, understands the full default Tailwind config out of the box, and can be extended to understand custom themes, plugins, and class groups via extendTailwindMerge and mergeConfigs.

What You Get

  • A single twMerge() function that merges any number of class strings/arrays and strips out conflicting Tailwind utilities.
  • A twJoin() helper for conditionally joining class names (a typed subset of clsx) when conflict resolution isn’t needed.
  • extendTailwindMerge, createTailwindMerge, and mergeConfigs for teaching the merge logic about a customized Tailwind theme or plugin classes.
  • Full TypeScript types for every export, plus a legacy ./es5 bundle for older browser targets.

Common Use Cases

  • Accepting an overridable className prop in a reusable component.
  • Merging variant classes generated by cva or tailwind-variants in a design system.
  • Resolving conditionally-applied Tailwind classes in state-driven UI.
  • Supporting a customized Tailwind theme with non-default spacing/color scales.

Under The Hood

Architecture — twMerge (src/lib/tw-merge.ts) is createTailwindMerge(getDefaultConfig): a factory in src/lib/create-tailwind-merge.ts that lazily builds its config and an LRU cache (src/lib/lru-cache.ts) on first call, then swaps its internal functionToCall reference to a fast cached path for every call after — avoiding config-parsing cost when twMerge is never invoked. The actual merge happens in mergeClassList (src/lib/merge-classlist.ts): the input is first joined by twJoin (a typed clsx subset, src/lib/tw-join.ts), then class names are walked right-to-left, each parsed by parseClassName (src/lib/parse-class-name.ts) into modifiers, base class, important-flag, and postfix-modifier position while tracking bracket/paren depth for arbitrary values like bg-[#B91C1C]. Each class resolves to a classGroupId via config-utils’ class-group matching (built from src/lib/default-config.ts and src/lib/validators.ts); a class is dropped if a later class already claimed the same modifier+classGroupId conflict key, with getConflictingClassGroupIds expanding transitive conflicts (e.g. px conflicts with pl and pr).

Tech Stack — Pure TypeScript with zero runtime dependencies ("dependencies": {} in package.json); built with Rollup (scripts/rollup.config.mjs) into separate ESM/CJS/ES5 bundles exposed via package.json’s exports map (. vs ./es5); tested with Vitest 4 plus @vitest/coverage-v8 for coverage and @codspeed/vitest-plugin for benchmark-regression tracking; linted with ESLint 9’s flat config and typescript-eslint; managed as a pnpm 11 workspace (pnpm-workspace.yaml) requiring Node >=22 via devEngines.runtime.

Code Quality — 36 test files under tests/ cover arbitrary values/properties/variants, class-group conflicts, the important modifier, negative values, lazy initialization, and even a docs-examples.test.ts that runs the README’s own code samples to keep documentation honest. A dedicated typescript-compat devDependency pins an older TypeScript version to verify the shipped .d.ts declarations stay compatible. Source modules are small and single-purpose (parse-class-name.ts, merge-classlist.ts, lru-cache.ts, sort-modifiers.ts are each well under 150 lines) with inline comments justifying non-obvious performance choices, such as the “Fast path: skip sorting for empty or single modifier” branch in merge-classlist.ts.

API Design — The zero-config twMerge default covers the common case with no setup (twMerge('a', 'b')), while power users extend behavior via extendTailwindMerge, createTailwindMerge, and mergeConfigs without forking internals, and fromTheme lets custom class groups key off the consumer’s own Tailwind theme. Bundle size is treated as a first-class concern (a Bundlephobia badge in the README, a dedicated ./es5 export for legacy targets), and documentation is split into task-oriented pages (what-is-it-for, when-and-how-to-use-it, configuration, recipes, api-reference, writing-plugins) rather than one long README.

Used by 219 apps in this directory

TypeScript
65%
MIT

Scalar

Developer Tools

16,198

Beautiful, interactive OpenAPI documentation with a built-in offline-first API client and multi-language code generation — all in one open-source platform.

View details
90
Repo Health
89
Technical
65
Dependency
Built with
TypeScript 65%
Vue 30%
Updated 1 weeks ago
Python
76%
Apache 2.0

Second Me

AI Assistants · Productivity

15,690

Train a locally hosted AI twin on your own memories—then connect it to the world through a decentralized identity network.

View details
41
Repo Health
75
Technical
67
Dependency
Built with
Python 76%
TypeScript 19%
Updated 1 years ago
Go
54%
MPL 2.0

shaper

Analytics · Data Engineering

1,251

Build analytics dashboards, reports, and customer-facing analytics by writing pure SQL — powered by DuckDB and designed for self-hosted deployment.

View details
80
Repo Health
79
Technical
74
Dependency
Built with
Go 54%
TypeScript 45%
Updated 1 weeks ago
TypeScript
95%
MIT

sigle

Blogging

489

A decentralized, open-source writing platform that permanently stores your stories on the Stacks blockchain and Arweave — where Web3 content creators own their words forever.

View details
81
Repo Health
78
Technical
69
Dependency
Built with
TypeScript 95%
Updated 1 weeks ago
TypeScript
51%
AGPL 3.0

Sink

Analytics · Bookmarks Archiving

7,173

Serverless link shortener with real-time analytics, powered by Cloudflare

View details
88
Repo Health
80
Technical
0
Dependency
Built with
TypeScript 51%
Vue 47%
Updated 1 weeks ago
Python
88%
Apache 2.0

sirchmunk

AI Development · Data Engineering

1,351

Drop your files and search them instantly — no vector DB, no indexing pipeline, just raw data queried by a self-evolving intelligence layer.

View details
84
Repo Health
70
Technical
72
Dependency
Built with
Python 88%
TypeScript 11%
Updated 2 weeks ago
Python
78%
AGPL 3.0

Skyvern

AI Agents · Automation

23,088

Skyvern (YC S2023) automates browser-based workflows by pairing LLMs with computer vision, letting agents click, fill, and extract data on sites they've never seen, without brittle XPath selectors that break on every layout change.

View details
89
Repo Health
82
Technical
70
Dependency
Built with
Python 78%
TypeScript 20%
Updated 1 weeks ago
TypeScript
97%
AGPL 3.0

Snapify

Collaboration · Productivity

1,018

Open-source, self-hostable screen recording and video sharing built as a Loom alternative — no accounts required to watch, full S3-backed storage for your data.

View details
38
Repo Health
68
Technical
70
Dependency
Built with
TypeScript 97%
Updated 1 years ago
PHP
46%
AGPL 3.0

solidtime

Invoicing Finance · Productivity

8,933

Modern open-source time tracker for freelancers and agencies with invoicing, multi-org support, and Toggl/Clockify migration built in.

View details
84
Repo Health
81
Technical
70
Dependency
Built with
PHP 46%
TypeScript 29%
Vue 22%
Updated 1 weeks ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers