The problem
A keyframe that animatestransform overwrites whatever transform the element
already had. In Tailwind v3 that includes rotate-45, scale-110 and
-translate-y-1, so adding a motion class could silently delete a layout
decision:
The fix
CSS has individualtranslate, scale and rotate properties. They compose
with transform rather than replacing it: the browser applies translate, then
rotate, then scale, then whatever transform says.
TailMotion ships 90 keyframes. 15 of them touch only opacity, filter, colour or
clip-path and never had a transform to conflict with. Of the 75 that move an
element, 39 now animate the individual properties:
That covers every entrance, every exit, every presence class, every scroll class
and every stagger keyframe — the ones most likely to land on an element Tailwind
has already transformed.
tm-slide-block-start · tm-slide-block-end · tm-slide-inline-start ·
tm-slide-inline-end · tm-slide-block-out · tm-slide-inline-out ·
tm-scale-in · tm-scale-out · tm-pop · tm-zoom-in · tm-zoom-out ·
tm-drop-in · tm-rotate-in · tm-elastic · tm-reveal · tm-glide ·
tm-glide-right · tm-scale-fade · tm-rise · tm-pulse · tm-spin ·
tm-float · tm-drift · tm-shake · tm-wiggle · tm-bounce ·
every tm-presence-* · every tm-scroll-* · tm-stagger
Browser support for individual transform properties is Chrome 104, Safari 14.1,
Firefox 72 — older than most of the library’s other requirements.
The 36 that did not move
These still writetransform, and are documented rather than converted, because
converting them would change the motion.
If one of these lands on an element you have transformed with Tailwind, wrap it:
Keep hover hit targets stationary
A hover-triggered keyframe that moves or shrinks its own element can move the element’s hitbox out from under the pointer. That removes:hover, resets the
animation, returns the element under the pointer, and starts the cycle again.
Put the hover state on a stationary parent and the motion on its child:
group-hover: form for every prebuilt hover:
variant. Direct hover: remains useful for opacity-only effects and for cases
where the element’s hitbox does not move.
Stacking two keyframe classes
Two keyframe classes on one element do not both run. Whichever comes later in the stylesheet winsanimation-name; the other is discarded. That is a
property of CSS animations, not of this library, and no amount of transform
safety changes it.
tm-scale-in and tm-pop fade and
scale, tm-slide-* fades and travels. Most requests for “fade plus slide” are
already one class.
Interaction and presence classes are transitions, not keyframes, so they do
stack on one element.
tm-press and tm-hover-lift together are fine, as is
tm-press on an element that also carries a tm-presence-* class — they
transition different properties.What this does not claim
TailMotion does not claim arbitrary keyframe composition, because CSS does not provide it. What it claims, and what is verified:- A motion class can be added to a Tailwind-transformed element without silently removing the intended transform — for the 39 keyframes listed above and every transition-based class.
- The 36 that still overwrite
transformare named, grouped by reason, and have a documented wrapper workaround. npm run checkrecounts all three numbers on every build and fails if this page drifts from the stylesheet.- Two keyframe classes on one element is documented as unsupported rather than quietly producing one of them.