Skip to main content

Animations

Built-in keyframe animations, duration and easing CSS variables, and parametric transform utilities.

View as Markdown

Moraine provides CSS animations through the UnoCSS preset and Tailwind 4 plugin. Built-in keyframes and transform utilities read the duration variables shown below. Set these variables in CSS; UnoCSS theme overrides cover design tokens, not animation controls.

Built-in Animation Utilities#

The following animation utilities are registered by presetMoraine() and moraine/tailwind:

Utility Description Iteration
animate-mo-enter Composable entrance animation with opacity, scale, and translation. 1
animate-mo-exit Composable exit animation for overlays and disclosures. 1
animate-accordion-down Expand height from 0 to var(--mo-collapsible-content-height). 1
animate-accordion-up Collapse height from var(--mo-collapsible-content-height) to 0. 1
animate-spin Infinite 360-degree rotation for progress rings and spinners. Infinite
animate-carousel Continuous horizontal sliding translation (-100% to 100%). Infinite
animate-shimmer Linear horizontal sweep for Skeleton’s gradient overlay. Infinite
animate-carousel-rtl Reverse horizontal sliding translation (100% to -100%). Infinite
animate-carousel-vertical Continuous vertical sliding translation (100% to -100%). Infinite
animate-swing Oscillating horizontal swing (-60% to 60%). Infinite
animate-swing-vertical Oscillating vertical swing (60% to -60%). Infinite
animate-elastic Horizontal stretch and snap translation. Infinite
animate-elastic-vertical Vertical stretch and snap translation. Infinite

Parametric Transform Utilities#

animate-mo-enter and animate-mo-exit read parametric CSS variables defined by matching utility classes. Combine them to create custom entrance and exit choreographies without writing custom keyframes:

export function AnimatedPopover() {
  return (
    <div class="animate-mo-enter enter-opacity-0 enter-scale-95 enter-translate-y-2">
      Dropdown or popover content
    </div>
  )
}
Utility pattern Target variable Values Example
enter-opacity-<val> --mo-enter-opacity 0–100 percentage enter-opacity-0, enter-opacity-50
exit-opacity-<val> --mo-exit-opacity 0–100 percentage exit-opacity-0
enter-scale-<val> --mo-enter-scale Scale percentage or arbitrary enter-scale-90, enter-scale-95
exit-scale-<val> --mo-exit-scale Scale percentage or arbitrary exit-scale-95
enter-translate-x-<val> --mo-enter-translate-x Spacing or arbitrary enter-translate-x-4, -enter-translate-x-2
enter-translate-y-<val> --mo-enter-translate-y Spacing or arbitrary enter-translate-y-2, -enter-translate-y-4
exit-translate-x-<val> --mo-exit-translate-x Spacing or arbitrary exit-translate-x-2
exit-translate-y-<val> --mo-exit-translate-y Spacing or arbitrary exit-translate-y-2
enter-rotate-<val> --mo-enter-rotate Degrees or arbitrary enter-rotate-12, -enter-rotate-45
exit-rotate-<val> --mo-exit-rotate Degrees or arbitrary exit-rotate-12

Animation Durations and Easing#

Moraine defines default durations and easing curves for each animation type:

:root {
  /* Global override for all Moraine CSS animations */
  --mo-anim-duration: 250ms;

  /* Type-specific overrides */
  --mo-anim-duration-enter: 250ms;
  --mo-anim-duration-exit: 150ms;
  --mo-anim-duration-loop: 2s;
  --mo-anim-duration-spin: 1s;

  /* Shared easing override for mo-enter and mo-exit */
  --mo-anim-ease: ease;
}
  • --mo-anim-duration overrides every Moraine animation duration when defined.
  • If --mo-anim-duration is not set, each animation falls back to its type-specific duration (enter, exit, loop, or spin).
  • --mo-anim-ease overrides the easing of animate-mo-enter and animate-mo-exit in its scope. When unset, they read --mo-anim-ease-enter and --mo-anim-ease-exit, respectively, then fall back to the curves below. Set these variables on the animated element or a DOM ancestor; portaled content cannot inherit from a trigger’s container outside the portal.
  • Easing curves:
    • enter: cubic-bezier(0.16, 1, 0.3, 1) (snappy ease-out)
    • exit: cubic-bezier(0.7, 0, 0.84, 0) (accelerating ease-in)
    • loop: ease-in-out
    • spin: linear

animate-shimmer uses the loop duration with linear easing.

Disclosure Height Token#

Collapsible and Accordion components calculate their rendered panel dimensions and set --mo-collapsible-content-height on the disclosure container element. The animate-accordion-down and animate-accordion-up keyframes read this variable to animate smoothly between 0 and the exact natural content height.

@keyframes accordion-down {
  from {
    height: 0;
    opacity: 0;
  }
  to {
    height: var(--mo-collapsible-content-height);
    opacity: 1;
  }
}

Reduced Motion#

To respect user preferences for reduced motion, pair animation utilities with motion-reduce:animate-none or motion-reduce:transition-none:

<div class="animate-mo-enter enter-opacity-0 enter-scale-95 motion-reduce:animate-none">
  Dialog content
</div>