0
# tailwind-merge
1
2
tailwind-merge is a utility function to efficiently merge Tailwind CSS classes in JavaScript without style conflicts. It provides intelligent conflict resolution that understands Tailwind's class precedence rules, allowing developers to programmatically combine CSS classes while ensuring the final result maintains proper styling without conflicting declarations.
3
4
## Package Information
5
6
- **Package Name**: tailwind-merge
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install tailwind-merge`
10
11
## Core Imports
12
13
```typescript
14
import { twMerge, twJoin, createTailwindMerge, extendTailwindMerge, getDefaultConfig, mergeConfigs, fromTheme } from "tailwind-merge";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { twMerge, twJoin, createTailwindMerge, extendTailwindMerge, getDefaultConfig, mergeConfigs, fromTheme } = require("tailwind-merge");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { twMerge } from "tailwind-merge";
27
28
// Basic merging with conflict resolution
29
const result = twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]');
30
// → 'hover:bg-dark-red p-3 bg-[#B91C1C]'
31
32
// Handle conditional classes
33
const buttonClasses = twMerge(
34
'px-4 py-2 rounded-md font-medium',
35
isLoading && 'opacity-50 cursor-not-allowed',
36
variant === 'primary' && 'bg-blue-500 text-white',
37
variant === 'secondary' && 'bg-gray-200 text-gray-900',
38
size === 'sm' && 'px-2 py-1 text-sm',
39
size === 'lg' && 'px-6 py-3 text-lg'
40
);
41
```
42
43
## Architecture
44
45
tailwind-merge is built around several key components:
46
47
- **Core Merger**: `twMerge` function that handles conflict resolution using the default Tailwind configuration
48
- **Class Joiner**: `twJoin` function for conditional class joining without conflict resolution
49
- **Configuration System**: Extensible configuration allowing customization of class groups and conflict rules
50
- **Factory Functions**: `createTailwindMerge` and `extendTailwindMerge` for creating custom merge instances
51
- **Validation System**: Comprehensive validators for different types of Tailwind class values
52
- **Performance Optimization**: LRU caching and efficient parsing for high-frequency usage
53
54
## Capabilities
55
56
### Core Merging Functions
57
58
Primary functions for merging and joining Tailwind CSS classes with conflict resolution and conditional handling.
59
60
```typescript { .api }
61
function twMerge(...classLists: ClassNameValue[]): string;
62
function twJoin(...classLists: ClassNameValue[]): string;
63
64
type ClassNameValue = ClassNameArray | string | null | undefined | 0 | 0n | false;
65
type ClassNameArray = ClassNameValue[];
66
```
67
68
[Core Functions](./core-functions.md)
69
70
### Configuration and Customization
71
72
Advanced configuration system for extending or customizing tailwind-merge behavior with custom class groups, theme scales, and conflict resolution rules.
73
74
```typescript { .api }
75
function extendTailwindMerge<
76
AdditionalClassGroupIds extends string = never,
77
AdditionalThemeGroupIds extends string = never,
78
>(
79
configExtension: ConfigExtension<
80
DefaultClassGroupIds | AdditionalClassGroupIds,
81
DefaultThemeGroupIds | AdditionalThemeGroupIds
82
>,
83
...createConfig: CreateConfigSubsequent[]
84
): TailwindMerge;
85
86
function createTailwindMerge(
87
createConfigFirst: () => AnyConfig,
88
...createConfigRest: CreateConfigSubsequent[]
89
): TailwindMerge;
90
91
function getDefaultConfig(): Config<DefaultClassGroupIds, DefaultThemeGroupIds>;
92
```
93
94
[Configuration](./configuration.md)
95
96
### Validation System
97
98
Comprehensive validation functions for different types of Tailwind class values, used in custom configurations and class group definitions.
99
100
```typescript { .api }
101
interface Validators {
102
isLength(value: string): boolean;
103
isArbitraryLength(value: string): boolean;
104
isNumber(value: string): boolean;
105
isInteger(value: string): boolean;
106
isPercent(value: string): boolean;
107
isArbitraryValue(value: string): boolean;
108
isTshirtSize(value: string): boolean;
109
isArbitrarySize(value: string): boolean;
110
isArbitraryPosition(value: string): boolean;
111
isArbitraryImage(value: string): boolean;
112
isArbitraryNumber(value: string): boolean;
113
isArbitraryShadow(value: string): boolean;
114
isAny(): boolean;
115
}
116
```
117
118
[Validation System](./validation.md)
119
120
## Types
121
122
```typescript { .api }
123
interface Config<ClassGroupIds extends string, ThemeGroupIds extends string>
124
extends ConfigStaticPart, ConfigGroupsPart<ClassGroupIds, ThemeGroupIds> {}
125
126
interface ConfigExtension<ClassGroupIds extends string, ThemeGroupIds extends string>
127
extends Partial<ConfigStaticPart> {
128
override?: PartialPartial<ConfigGroupsPart<ClassGroupIds, ThemeGroupIds>>;
129
extend?: PartialPartial<ConfigGroupsPart<ClassGroupIds, ThemeGroupIds>>;
130
}
131
132
type ClassValidator = (classPart: string) => boolean;
133
134
type DefaultClassGroupIds = 'accent' | 'align-content' | 'align-items' | 'align-self' | 'animate' | 'appearance' | 'aspect' | 'auto-cols' | 'auto-rows' | 'backdrop-blur' | 'backdrop-brightness' | 'backdrop-contrast' | 'backdrop-filter' | 'backdrop-grayscale' | 'backdrop-hue-rotate' | 'backdrop-invert' | 'backdrop-opacity' | 'backdrop-saturate' | 'backdrop-sepia' | 'basis' | 'bg-attachment' | 'bg-blend' | 'bg-clip' | 'bg-color' | 'bg-image' | 'bg-opacity' | 'bg-origin' | 'bg-position' | 'bg-repeat' | 'bg-size' | 'blur' | 'border-collapse' | 'border-color-b' | 'border-color-e' | 'border-color-l' | 'border-color-r' | 'border-color-s' | 'border-color-t' | 'border-color-x' | 'border-color-y' | 'border-color' | 'border-opacity' | 'border-spacing-x' | 'border-spacing-y' | 'border-spacing' | 'border-style' | 'border-w-b' | 'border-w-e' | 'border-w-l' | 'border-w-r' | 'border-w-s' | 'border-w-t' | 'border-w-x' | 'border-w-y' | 'border-w' | 'bottom' | 'box-decoration' | 'box' | 'break-after' | 'break-before' | 'break-inside' | 'break' | 'brightness' | 'caption' | 'caret-color' | 'clear' | 'col-end' | 'col-start-end' | 'col-start' | 'columns' | 'container' | 'content' | 'contrast' | 'cursor' | 'delay' | 'display' | 'divide-color' | 'divide-opacity' | 'divide-style' | 'divide-x-reverse' | 'divide-x' | 'divide-y-reverse' | 'divide-y' | 'drop-shadow' | 'duration' | 'ease' | 'end' | 'fill' | 'filter' | 'flex-direction' | 'flex-wrap' | 'flex' | 'float' | 'font-family' | 'font-size' | 'font-smoothing' | 'font-style' | 'font-weight' | 'forced-color-adjust' | 'fvn-figure' | 'fvn-fraction' | 'fvn-normal' | 'fvn-ordinal' | 'fvn-slashed-zero' | 'fvn-spacing' | 'gap-x' | 'gap-y' | 'gap' | 'gradient-from-pos' | 'gradient-from' | 'gradient-to-pos' | 'gradient-to' | 'gradient-via-pos' | 'gradient-via' | 'grayscale' | 'grid-cols' | 'grid-flow' | 'grid-rows' | 'grow' | 'h' | 'hue-rotate' | 'hyphens' | 'indent' | 'inset-x' | 'inset-y' | 'inset' | 'invert' | 'isolation' | 'justify-content' | 'justify-items' | 'justify-self' | 'leading' | 'left' | 'line-clamp' | 'list-image' | 'list-style-position' | 'list-style-type' | 'm' | 'max-h' | 'max-w' | 'mb' | 'me' | 'min-h' | 'min-w' | 'mix-blend' | 'ml' | 'mr' | 'ms' | 'mt' | 'mx' | 'my' | 'object-fit' | 'object-position' | 'opacity' | 'order' | 'outline-color' | 'outline-offset' | 'outline-style' | 'outline-w' | 'overflow-x' | 'overflow-y' | 'overflow' | 'overscroll-x' | 'overscroll-y' | 'overscroll' | 'p' | 'pb' | 'pe' | 'pl' | 'place-content' | 'place-items' | 'place-self' | 'placeholder-color' | 'placeholder-opacity' | 'pointer-events' | 'position' | 'pr' | 'ps' | 'pt' | 'px' | 'py' | 'resize' | 'right' | 'ring-color' | 'ring-offset-color' | 'ring-offset-w' | 'ring-opacity' | 'ring-w-inset' | 'ring-w' | 'rotate' | 'rounded-b' | 'rounded-bl' | 'rounded-br' | 'rounded-e' | 'rounded-ee' | 'rounded-es' | 'rounded-l' | 'rounded-r' | 'rounded-s' | 'rounded-se' | 'rounded-ss' | 'rounded-t' | 'rounded-tl' | 'rounded-tr' | 'rounded' | 'row-end' | 'row-start-end' | 'row-start' | 'saturate' | 'scale-x' | 'scale-y' | 'scale' | 'scroll-behavior' | 'scroll-m' | 'scroll-mb' | 'scroll-me' | 'scroll-ml' | 'scroll-mr' | 'scroll-ms' | 'scroll-mt' | 'scroll-mx' | 'scroll-my' | 'scroll-p' | 'scroll-pb' | 'scroll-pe' | 'scroll-pl' | 'scroll-pr' | 'scroll-ps' | 'scroll-pt' | 'scroll-px' | 'scroll-py' | 'select' | 'sepia' | 'shadow-color' | 'shadow' | 'shrink' | 'size' | 'skew-x' | 'skew-y' | 'snap-align' | 'snap-stop' | 'snap-strictness' | 'snap-type' | 'space-x-reverse' | 'space-x' | 'space-y-reverse' | 'space-y' | 'sr' | 'start' | 'stroke-w' | 'stroke' | 'table-layout' | 'text-alignment' | 'text-color' | 'text-decoration-color' | 'text-decoration-style' | 'text-decoration-thickness' | 'text-decoration' | 'text-opacity' | 'text-overflow' | 'text-transform' | 'text-wrap' | 'top' | 'touch-pz' | 'touch-x' | 'touch-y' | 'touch' | 'tracking' | 'transform-origin' | 'transform' | 'transition' | 'translate-x' | 'translate-y' | 'underline-offset' | 'vertical-align' | 'visibility' | 'w' | 'whitespace' | 'will-change' | 'z';
135
136
type DefaultThemeGroupIds = 'blur' | 'borderColor' | 'borderRadius' | 'borderSpacing' | 'borderWidth' | 'brightness' | 'colors' | 'contrast' | 'gap' | 'gradientColorStopPositions' | 'gradientColorStops' | 'grayscale' | 'hueRotate' | 'inset' | 'invert' | 'margin' | 'opacity' | 'padding' | 'saturate' | 'scale' | 'sepia' | 'skew' | 'space' | 'spacing' | 'translate';
137
138
interface ExperimentalParseClassNameParam {
139
className: string;
140
parseClassName(className: string): ExperimentalParsedClassName;
141
}
142
143
interface ExperimentalParsedClassName {
144
modifiers: string[];
145
hasImportantModifier: boolean;
146
baseClassName: string;
147
maybePostfixModifierPosition: number | undefined;
148
}
149
```