Skip to Content
v2 is on npm — atomic classes for Tailwind CSS
Preserve & runtime

Preserve & runtime

What is left untouched

The Rust (WASM) engine only atomicizes utility rules. These stay as they are:

  • @theme
  • :root
  • preflight
  • @keyframes
  • nested at-rules (@media, @supports, @container)

The rest of each selector is kept: ._hash:hover, space-y-* combinators, the @media of sm:. Hover and breakpoints survive.

Custom classes that are not Tailwind-shaped (.header-signin) stay intact. Names that do look like utilities (text-logo, flex-container) need preserveClasses.

twIgnore

Wrap strings that must not be rewritten:

import {twIgnore} from "tailwindcss-atomic/runtime"; <div className={twIgnore("flex hidden")} />

Add extra names via preserveFunctions if your codebase uses another helper.

Runtime cn / Tailwind Merge

If you use tailwind-merge at runtime, hashed classes no longer look like Tailwind utilities. The bundler wraps cn / clsx / cx / twMerge with _twAtomicReconcile: it unhashes, runs twMerge, then hashes again. Merge still sees original tokens.

Most apps do not need to import runtime yourself: rewrite happens at build time. Reach for twIgnore when class strings must stay literal.

bg-opacity-* drops the color (tailwind-merge v3)

With tailwind-merge v3 (Tailwind CSS v4), bg-opacity-50 is treated as another bg-* color. The last class wins and the real color is removed:

twMerge("bg-neutral-300 bg-opacity-50"); // → "bg-opacity-50"

In the DOM you still see the hash for bg-opacity-50 (--tw-bg-opacity: .5) and no background-color. The same happens with text-opacity-* and border-opacity-*.

This is not a hashing bug. It shows up on cx() / cn() components (those calls are reconciled). A cva() recipe is not wrapped, so it can look “fine” next to a skeleton that lost its fill.

Use the slash modifier instead of the two-class form:

// ❌ tailwind-merge v3 drops bg-neutral-300 cx("rounded-lg bg-neutral-300 bg-opacity-50", className); // ✅ one utility: color + opacity cx("rounded-lg bg-neutral-300/50", className);

Same pattern: text-black/50, border-neutral-300/50. See tailwind-merge#579 .

Last updated on