https://github.com/magicdawn/unocss-merge
simple utility to merge unocss class names
https://github.com/magicdawn/unocss-merge
Last synced: 29 days ago
JSON representation
simple utility to merge unocss class names
- Host: GitHub
- URL: https://github.com/magicdawn/unocss-merge
- Owner: magicdawn
- License: mit
- Created: 2025-04-25T02:06:22.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-06-06T04:28:58.000Z (29 days ago)
- Last Synced: 2026-06-06T05:23:45.458Z (29 days ago)
- Language: TypeScript
- Size: 724 KB
- Stars: 14
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# unocss-merge
> simple utility to merge unocss class names, see https://github.com/unocss/unocss/issues/2748
[](https://github.com/magicdawn/unocss-merge/actions/workflows/ci.yml)
[](https://codecov.io/gh/magicdawn/unocss-merge)
[](https://www.npmjs.com/package/unocss-merge)
[](https://www.npmjs.com/package/unocss-merge)
[](http://magicdawn.mit-license.org)
## Install
```sh
$ pnpm add unocss-merge
```
## API
### `unoMerge`
```ts
import { unoMerge } from 'unocss-merge'
expect(unoMerge('hidden', 'block')).toBe('block')
expect(unoMerge('hidden', 'block', 'flex')).toBe('flex')
expect(unoMerge('mr-1', 'mr-2')).toBe('mr-2')
expect(unoMerge('mr-1', 'mr-4px')).toBe('mr-4px')
expect(unoMerge('mr-1', 'mr-[-4px]')).toBe('mr-[-4px]')
expect(unoMerge('mr-1', 'mr--4px')).toBe('mr--4px')
expect(unoMerge('cursor-pointer', 'cursor-not-allowed')).toBe('cursor-not-allowed')
```
> [!TIP]
> This function does not provide any cache mechanism, use `unoMergeMemoized` or wrap with your own cache if needed.
### `useUnoMerge`
```tsx
import { useUnoMerge } from 'unocss-merge/react'
function Component(props) {
const className = useUnoMerge('cursor-pointer', props.className)
return
}
```
> [!TIP]
> this is a simple wrapper of `React.useMemo`, so arguments.length should not change in runtime
> require `react` as peer dependency
### `unoMergeMemoized`
```tsx
import { unoMergeMemoized } from 'unocss-merge/memoize'
expect(unoMergeMemoized('hidden', 'block')).toBe('block')
expect(unoMergeMemoized('hidden', 'block', 'flex')).toBe('flex')
expect(unoMergeMemoized('mr-1', 'mr-2')).toBe('mr-2')
expect(unoMergeMemoized('mr-1', 'mr-4px')).toBe('mr-4px')
expect(unoMergeMemoized('mr-1', 'mr-[-4px]')).toBe('mr-[-4px]')
expect(unoMergeMemoized('mr-1', 'mr--4px')).toBe('mr--4px')
expect(unoMergeMemoized('cursor-pointer', 'cursor-not-allowed')).toBe('cursor-not-allowed')
```
> [!TIP]
> this is a simple wrapper of `unoMerge` with [memoize](https://github.com/sindresorhus/memoize#install)
> require `memoize` as peer dependency
## Why
- No Official One: https://github.com/unocss/unocss/issues/2748
- `twMerge` don't support [arbitrary value without brackets](https://github.com/dcastil/tailwind-merge/blob/v3.2.0/src/lib/validators.ts#L1)
```ts
import { twMerge } from 'tailwind-merge' // "tailwind-merge": "^3.2.0",
// size-16px ml-4px cursor-not-allowed size-18px ml-10px
console.log(twMerge('cursor-pointer size-16px ml-4px', 'cursor-not-allowed size-18px ml-10px'))
console.log(twMerge('cursor-pointer', 'cursor-not-allowed')) // `cursor-not-allowed` ✅
console.log(twMerge('size-[16px]', 'size-[18px]')) // `size-[18px]` ✅
console.log(twMerge('ml-[4px]', 'ml-[10px]')) // `ml-[10px]` ✅
// twMerge don't support arbitrary value without brackets
console.log(twMerge('size-16px', 'size-18px')) // `size-16px size-18px` ❌
console.log(twMerge('ml-4px', 'ml-10px')) // `ml-4px ml-10px` ❌
```
## Status
### ✅ What is **KNOWN** Supported
- ✅ simple class name `mr-4px` `mr-4`
- ✅ value in brackets `mr-[4px]` `mr-[4]`
- ✅ negative value `mr--4px`
- ✅ simple colon separated variants `hover:mr-4px` `dark:ml-4px` `hover:dark:ml-4px`
- ✅ simple shorthand: supports `margin` & `padding`, like `m-1` `mx-1` `ml-1` `mr-1`
- ✅ `mx-2` overwrite `ml-1` & `mr-1`
- ✅ `m-2` overwrite `mx-1` & `mr-1`
- ✅ merge multiple important utilities
```ts
expect(unoMerge('mr-4px mr-2px!')).toBe('mr-4px mr-2px!')
expect(unoMerge('mr-4px mr-2px! !mr-1')).toBe('mr-4px !mr-1')
expect(unoMerge('mr-4px mr-2px! !mr-1 important:mr-2')).toBe('mr-4px important:mr-2')
```
### ❌ What is **NOT** Supported
- complex features are not supported !!!
- ❌ [Complex Variants](https://github.com/unocss/unocss/tree/main/packages-presets/preset-mini/src/_variants) are not recongized
- ❌ [Variant Group](https://unocss.dev/transformers/variant-group) U should setup [Variant group transformer](https://unocss.dev/transformers/variant-group)
- ❌ [Shortcuts](https://unocss.dev/config/shortcuts) are not recongized
- ❌ complex shorthand: I don't recall any example in my mind
### Support Scope
Utility classNames listed on [tailwindcss v3 documentation](https://v3.tailwindcss.com/docs/installation) are in the support scope.
> [!CAUTION]
> Yes, it's `UnoCSS-merge`, while based on `tailwindcss` v3 documentation, since unocss (technically unocss is an engine, the core presets `@unocss/preset-wind*`) has no document pages for utility classNames.
> If something listed, but not supported, please open an [issue](https://github.com/magicdawn/unocss-merge/issues)
#### unocss `Too Flexible`
for example `mr-1`
1. `m-r-1` / `m-r1` / `mr-1` / `mr1` are all valid for unocss presetWind3.
2. [tailwindcss v3 documentation](https://v3.tailwindcss.com/docs/margin) using `mr-1`, unocss has no document pages.
3. So only `mr-1` is supported.
## Changelog
See https://github.com/magicdawn/unocss-merge/releases
## License
the MIT License http://magicdawn.mit-license.org