Skip to content

Commit

Permalink
add support for important modifier at the end of base class name
Browse files Browse the repository at this point in the history
  • Loading branch information
dcastil committed Jan 26, 2025
1 parent bd2e7b3 commit 94e9e26
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 10 deletions.
4 changes: 2 additions & 2 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ The order of standard modifiers before and after an arbitrary variant in isolati
### Supports important modifier

```ts
twMerge('!p-3 !p-4 p-5') // → '!p-4 p-5'
twMerge('!right-2 !-inset-x-1') // → '!-inset-x-1'
twMerge('p-3! p-4! p-5') // → 'p-4! p-5'
twMerge('right-2! -inset-x-1!') // → '-inset-x-1!'
```

### Supports postfix modifiers
Expand Down
4 changes: 2 additions & 2 deletions docs/when-and-how-to-use-it.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ function MyComponent() {
return (
<>
<Button className="w-full">No danger</Button>
<Button className="w-full !bg-red-500" >Danger!</Button>
<Button className="w-full bg-red-500!" >Danger!</Button>
</>
)
}
Expand All @@ -158,7 +158,7 @@ function join(...args) {
}
```

The main downside of this approach is that it only works one level deep (you can't override the `!bg-red-500` class in the example above). But if you don't need to be able to override styles through multiple levels of composition, this might be the most lightweight approach possible.
The main downside of this approach is that it only works one level deep (you can't override the `bg-red-500!` class in the example above). But if you don't need to be able to override styles through multiple levels of composition, this might be the most lightweight approach possible.

---

Expand Down
24 changes: 18 additions & 6 deletions src/lib/parse-class-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,8 @@ export const createParseClassName = (config: AnyConfig) => {

const baseClassNameWithImportantModifier =
modifiers.length === 0 ? className : className.substring(modifierStart)
const hasImportantModifier =
baseClassNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER)
const baseClassName = hasImportantModifier
? baseClassNameWithImportantModifier.substring(1)
: baseClassNameWithImportantModifier

const baseClassName = stripImportantModifier(baseClassNameWithImportantModifier)
const hasImportantModifier = baseClassName !== baseClassNameWithImportantModifier
const maybePostfixModifierPosition =
postfixModifierPosition && postfixModifierPosition > modifierStart
? postfixModifierPosition - modifierStart
Expand Down Expand Up @@ -104,3 +100,19 @@ export const sortModifiers = (modifiers: string[]) => {

return sortedModifiers
}

const stripImportantModifier = (baseClassName: string) => {
if (baseClassName.endsWith(IMPORTANT_MODIFIER)) {
return baseClassName.substring(0, baseClassName.length - 1)
}

/**
* In Tailwind CSS v3 the important modifier was at the start of the base class name. This is still supported for legacy reasons.
* @see https://github.com/dcastil/tailwind-merge/issues/513#issuecomment-2614029864
*/
if (baseClassName.startsWith(IMPORTANT_MODIFIER)) {
return baseClassName.substring(1)
}

return baseClassName
}
11 changes: 11 additions & 0 deletions tests/important-modifier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,19 @@ import { expect, test } from 'vitest'
import { twMerge } from '../src'

test('merges tailwind classes with important modifier correctly', () => {
expect(twMerge('font-medium! font-bold!')).toBe('font-bold!')
expect(twMerge('font-medium! font-bold! font-thin')).toBe('font-bold! font-thin')
expect(twMerge('right-2! -inset-x-px!')).toBe('-inset-x-px!')
expect(twMerge('focus:inline! focus:block!')).toBe('focus:block!')
expect(twMerge('[--my-var:20px]! [--my-var:30px]!')).toBe('[--my-var:30px]!')

// Tailwind CSS v3 legacy syntax

expect(twMerge('font-medium! !font-bold')).toBe('!font-bold')

expect(twMerge('!font-medium !font-bold')).toBe('!font-bold')
expect(twMerge('!font-medium !font-bold font-thin')).toBe('!font-bold font-thin')
expect(twMerge('!right-2 !-inset-x-px')).toBe('!-inset-x-px')
expect(twMerge('focus:!inline focus:!block')).toBe('focus:!block')
expect(twMerge('![--my-var:20px] ![--my-var:30px]')).toBe('![--my-var:30px]')
})

0 comments on commit 94e9e26

Please sign in to comment.