Layers and conflict resolution
Tailwind Variants' default build drops conflicting utilities with tailwind-merge. UnoCSS Variants does not. Every class you put in base, variants, compounds, extend, and class / className is concatenated and returned.
That is deliberate: the CSS cascade and specificity stay visible. The uv-no-merge tests in the package assert that conflicts are preserved.
What that means
import { uv } from 'unocss-variants';
const button = uv({
base: 'px-4 py-2 rounded'
});
button({ class: 'px-2 py-4 rounded-lg' });
// px-4 py-2 rounded px-2 py-4 rounded-lg
Both px-4 and px-2 are in the string. Which padding you see depends on stylesheet order, not on which token appears last in the class attribute.
The same applies to extend: parent bg-zinc-100 and child bg-blue-500 both remain unless the child is assigned a later CSS layer.
Configure a uv layer
UnoCSS can emit utilities into named CSS layers. Give uv a higher order than the default layer, then prefix the utilities that must win:
import { defineConfig } from 'unocss';
export default defineConfig({
layers: {
// Default utilities sit below this. Higher number = later in CSS = wins.
uv: 10
}
});
Prefix classes that should win
The uno-layer-<name>: variant puts a utility into that layer:
const buyButton = uv({
extend: baseButton,
base: [
'rounded-lg',
'uno-layer-uv:bg-blue-500',
'uno-layer-uv:hover:bg-blue-600'
]
});
bg-zinc-100 from the parent (default layer) and uno-layer-uv:bg-blue-500 from the child both exist in the class list. The uv layer is emitted later, so the button is blue.
Use the same prefix on:
- Child recipe classes that override a parent
- Compound variant backgrounds that override a color variant
- Call-site
classoverrides that must beat the recipe
Skip the prefix when there is no conflict (layout, typography, shadows).
Suggested cascade
A practical order when a recipe is applied:
base- Variant classes
- Compound variants / compound slots
- Call-site
class/className
Because nothing is removed, step 4 does not automatically override step 2. If a call-site class conflicts with a variant, prefix the call-site class (or the variant) with uno-layer-uv:.
What not to do
- Do not install
tailwind-mergeforuv— it is not wired up, and there is notwMergeconfig flag. - Do not assume later tokens in the string win. That is merge-library behavior, not CSS.
- Do not look for
createTV, a seconduv(options, config)argument, orunocss-variants/lite.