Skip to content

Motion

@simurgh-ui/motion adds purposeful animation without changing the default behavior of Simurgh components. Durations and delays use seconds. The engine uses the Web Animations API and imports safely during server rendering.

Terminal window
pnpm add @simurgh-ui/motion

These examples use the React adapter, but the motion definitions are shared by every adapter. They cover transform keyframes, spring gestures, enter and exit presence, staggered children, viewport intersection, and an explicit reduced-motion setting. The default reducedMotion: "user" setting automatically removes duration when the operating system requests reduced motion.

Live component Motion patterns

Keyframes

Combine transform and opacity arrays in one timeline.

Spring gestures

Hover, focus, or press the button.

Presence

Content remains mounted until its exit animation completes.

Staggered children

  • Plan
  • Build
  • Verify

In-view motion

Elements animate when they intersect the viewport.

Discover
Compose
Deliver

Reduced motion

Product settings can override the operating-system preference.

Use gesture states for immediate feedback, Presence when removed content needs an exit animation, and stagger on a parent definition to sequence bound children. Motion should reinforce a state change; it should not delay focus, validation, or access to content.

Transform shorthands accept a single value or an array. Arrays with different lengths are sampled across the same timeline, and numeric x, y, and rotate values receive pixel and degree units.

const celebration = {
opacity: [0, 1, 1, 1],
scale: [0.8, 1.08, 0.96, 1],
rotate: [0, 8, -5, 0],
};
animate(element, celebration, {
duration: 0.65,
easing: 'ease-in-out',
});

The same primitives can produce application-level effects without a special component for every pattern. These examples adapt common animation ideas—typewriter text, staggered character reveal, accordion reveal, loading shimmer, a timeline sequence, and SVG path drawing—to Simurgh’s smaller API.

Live component Interface motion patterns

Typewriter

Motion tells a story.

Character reveal

Build with motion

Accordion reveal

Skeleton shimmer

Timeline sequence

123

SVG path drawing

The accordion preserves aria-expanded and its controlled-region relationship. The loading bars are hidden from assistive technology, while the SVG retains an accessible name. Treat those semantics as part of the example rather than decoration to remove when copying it.

These GSAP-inspired examples synchronize several property tracks to create an orbital path, a repeating marquee, and a shape-and-color transformation. They use ordinary keyframe arrays, so no plugin or browser-global setup is required.

Live component Choreographed motion

Orbital keyframes

Looping marquee

Shape and color

An x array and a y array with matching lengths approximate a path through a series of points. This is useful for small decorative routes; use a dedicated path engine when an object must follow an arbitrary SVG curve precisely. Repeated motion still follows the configured reduced-motion mode.

import { animate, sequence } from '@simurgh-ui/motion';
const controls = animate(
card,
{ opacity: [0, 1], y: [8, 0] },
{
type: 'spring',
stiffness: 180,
damping: 24,
},
);
await sequence([
[heading, { opacity: [0, 1] }],
[actions, { opacity: [0, 1], y: [4, 0] }, { delay: 0.04 }],
]).finished;
controls.pause();
controls.play();
controls.cancel();
import { animated, Presence } from '@simurgh-ui/motion/react';
import { Button } from '@simurgh-ui/react/button';
const itemMotion = {
initial: { opacity: 0, y: 6 },
animate: { opacity: 1, y: 0 },
whileHover: { scale: 1.02 },
whilePress: { scale: 0.98 },
exit: { opacity: 0, y: -4 },
};
<Presence exit={itemMotion}>
{open && (
<animated.div key="panel" motion={itemMotion}>
<Button>Save</Button>
</animated.div>
)}
</Presence>;

useMotion(definition) returns an element ref and controls for cases where a wrapper is not useful.

<script setup lang="ts">
import { Motion, Presence } from '@simurgh-ui/motion/vue';
const panel = {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
};
</script>
<Presence
:exit="panel"
><Motion v-if="open" :motion="panel"><button>Save</button></Motion></Presence>

Use v-motion="definition" or useMotion(definition) when an extra component is undesirable.

import {
SimurghMotionDirective,
SimurghPresence,
} from '@simurgh-ui/motion/angular';
@Component({
imports: [SimurghMotionDirective, SimurghPresence],
template: `<simurgh-presence [present]="open" [motion]="panel">
<section [simurghMotion]="panel">Content</section>
</simurgh-presence>`,
})
export class Example {
open = true;
panel = {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
};
}

Definitions accept named variants and the states whileHover, whilePress, whileFocus, and whileInView. A state may contain keyframes directly or name a variant. Delays and stagger are expressed in seconds.

Bind a motion definition to both the parent and its children. The parent adds its stagger delay to each child in document order.

const list = { animate: { opacity: 1 }, stagger: 0.3 };
const item = {
initial: { opacity: 0, x: -12 },
animate: { opacity: [0, 1], x: [-18, 0] },
transition: { duration: 0.45 },
};
<animated.ul motion={list}>
{items.map((label) => (
<animated.li key={label} motion={item}>{label}</animated.li>
))}
</animated.ul>

Use useMotion when adding an animated.* wrapper would change markup or component semantics.

import { useMotion } from '@simurgh-ui/motion/react';
function StatusMessage() {
const { ref, controls } = useMotion<HTMLParagraphElement>({
initial: { opacity: 0 },
animate: { opacity: 1 },
});
return (
<p ref={ref}>
Saved
<button type="button" onClick={() => controls.current?.play()}>
Replay
</button>
</p>
);
}

The default reducedMotion: "user" follows prefers-reduced-motion. Use "always" for a product setting that disables motion and "never" only for a necessary, non-spatial state transition. Reduced motion removes delays and repeats. Never delay focus, dismissal, or validation feedback until decorative animation finishes.

The CSS package exposes --simurgh-duration-fast, --simurgh-duration, --simurgh-duration-slow, --simurgh-ease-standard, and --simurgh-ease-emphasized.

Last verified on 2026-08-13 against Simurgh registry 0.1.1.