Skip to main content
TailMotion is a CSS package for the motion in a product interface. Tailwind owns layout, color, spacing, radius, shadows and typography. TailMotion owns how an element enters, exits, responds, repeats and reacts to state.
A keyframe collection answers “how do I fade this in?” TailMotion answers “how should this whole product move, and what happens when the state changes?”

What a keyframe collection cannot do

Fading something in is the easy part. The hard part is everything around it: making a whole surface feel calmer without editing 200 class names, animating the data-state your headless UI library already emits, giving <dialog> and [popover] an exit, and shipping a scroll reveal that fails safely in a browser that has never heard of view timelines.

Scoped motion personalities

One class on an ancestor retunes the feel of everything below it. The animation classes never change.

State-driven presence

Animates the data-state and aria-expanded your application already sets. Interruptible by construction.

Native HTML motion

Real entrances and exits for [popover], <dialog> and <details>, with the browser keeping focus and semantics.

Product recipes

Menu, dialog, toast, tooltip, accordion, tabs, loading-to-success and hold-to-confirm — as motion only.

Scroll-driven motion

CSS view timelines. No observer, no listener, and content stays visible where the browser has none.

Choreography

Stagger that can enter, exit and reverse — without reordering the DOM.

The shape of the library

Seven categories, each with one job. Interaction and presence are built from transitions because only they need to survive a change of mind mid-flight — a replayed keyframe would snap back to its start. Personality and choreography add no rules of their own: they are inherited custom properties every other category already reads. See the motion model for how the four token groups fit together, and which one do I want? for picking between them.

What is guaranteed

Every one of these is verified by npm run check, which fails the build if a class points at missing keyframes, a rule hides content outside an @supports guard, :root picks up a timing token, or a module ships without a reduced-motion reset.
  • Zero runtime in the CSS core. Importing the stylesheet adds no JavaScript. The optional helpers in tailmotion/utils are opt-in and no class requires them.
  • Nothing modern can hide content. A hidden base state is only ever declared inside the @supports block that also says how it comes back.
  • Reduced motion preserves the state. Animations collapse to 1ms rather than being removed, so what a class communicates still lands — it just lands instantly. Two classes are deliberate exceptions, for good reasons.
  • Direction is logical. Inline-axis motion mirrors in right-to-left contexts. Block-axis motion does not, because up is up in every writing direction.
  • Tailwind v3, Tailwind v4, and no Tailwind at all are all supported. The prebuilt stylesheet needs no build step and no plugin.

Non-goals

TailMotion will not grow into these, and it is worth saying so plainly.
  • No JavaScript animation runtime. If a behaviour needs one, it belongs in your application, not here.
  • No styled components for React, Vue or Svelte. One CSS API, four identical integrations.
  • No colors, sizes, spacing or radius in a motion class. That is Tailwind’s job, and mixing the two is how motion libraries become design systems nobody asked for.
  • No React Native. TailMotion is CSS and DOM selectors. See Support.

Where to go next

Quickstart

Install, import, and ship the first four behaviours.

Class reference

Every class, its trigger, its states, its timing and its required markup.