Introducing PrimeReact v11-alpha 🎉Discover Now

useMotion

Hook that manages enter/leave animations with CSS class transitions and visibility control.

Usage#

import { useMotion } from '@primereact/core/motion';
const ref = React.useRef<HTMLDivElement>(undefined);
const motion = useMotion({
    elementRef: ref,
    visible: isOpen,
    name: 'fade'
});
 
return <>{motion.state.rendered && <div ref={ref} {...motion.rootProps}></div>}</>;

useMotion runs a CSS class-based enter/leave animation lifecycle against a single element, returning rootProps for hidden styles and state.rendered for conditional mounting.

Features#

  • CSS class lifecycle — applies {name}-enter-from, {name}-enter-active, {name}-enter-to on enter and mirrored -leave-* classes on leave
  • Mount management — state.rendered combined with mountOnEnter / unmountOnLeave keeps the element in the DOM only while needed
  • Hide strategies — choose how closed content is hidden: display: none, visibility: hidden, or let CSS animations handle it entirely
  • Dimension variables — cssVarPrefix writes --{prefix}-height / --{prefix}-width on the element for collapsible transitions
  • Full lifecycle callbacks — eight hooks covering before/during/after/cancelled for both enter and leave phases
  • Imperative control — enter(), leave(), cancel(), and update() for programmatic transitions

Working with callbacks#

Drive animations with a name prefix#

Pick a name and define six CSS classes against that prefix. The hook applies them in order across the enter and leave phases.

const motion = useMotion({ elementRef: ref, visible, name: 'slide' });
.slide-enter-from {
    opacity: 0;
    transform: translateY(-10px);
}
.slide-enter-active {
    transition: all 200ms ease-out;
}
.slide-enter-to {
    opacity: 1;
    transform: translateY(0);
}
 
.slide-leave-from {
    opacity: 1;
    transform: translateY(0);
}
.slide-leave-active {
    transition: all 200ms ease-in;
}
.slide-leave-to {
    opacity: 0;
    transform: translateY(-10px);
}

Collapsible height transitions#

Set cssVarPrefix so the hook injects scroll-height into a CSS variable you can read from your transitions.

const motion = useMotion({ elementRef: ref, visible, cssVarPrefix: 'panel-content' });
.collapsible-enter-active,
.collapsible-leave-active {
    transition: max-height 300ms ease;
    overflow: hidden;
}
 
.collapsible-enter-to,
.collapsible-leave-from {
    max-height: var(--panel-content-height);
}
 
.collapsible-enter-from,
.collapsible-leave-to {
    max-height: 0;
}

Run the enter animation on mount#

Enable appear so the enter lifecycle plays the first time the element becomes visible, instead of jumping straight to its final state.

const motion = useMotion({ elementRef: ref, visible: true, appear: true, name: 'fade' });

React to phase transitions#

Use the lifecycle callbacks to coordinate side effects — trigger focus moves after enter, release listeners after leave, or clean up inline styles.

const motion = useMotion({
    elementRef: ref,
    visible,
    name: 'fade',
    onBeforeEnter: (e) => e.el.style.setProperty('will-change', 'opacity'),
    onAfterEnter: () => inputRef.current?.focus(),
    onAfterLeave: () => releaseScrollLock()
});
CallbackPhase
onBeforeEnterBefore enter transition starts
onEnterEnter transition starts
onAfterEnterEnter transition ends
onEnterCancelledEnter transition cancelled
onBeforeLeaveBefore leave transition starts
onLeaveLeave transition starts
onAfterLeaveLeave transition ends
onLeaveCancelledLeave transition cancelled

Imperative control#

Call enter(), leave(), or cancel() to drive the animation from outside a visibility prop, and update() to reconfigure the instance on an existing element.

const motion = useMotion({ elementRef: ref, visible, name: 'fade' });
 
motion.enter();
motion.leave();
motion.cancel();
motion.update(element, { name: 'slide', duration: 300 });

Hide strategy reference#

Switch hideStrategy to match what your CSS expects. display is the default because it removes the element from layout entirely.

ValueBehavior
'display'Applies display: none (default)
'visibility'Applies visibility: hidden and max-height: 0
'none'No automatic hiding — CSS animations handle it entirely

API#

useMotion#

NameTypeDefault
elementRefHTMLElement | RefObject<HTMLElement>—
The ref of the element to apply the motion to.
visiblebooleanfalse
Whether the element is visible or not.
mountOnEnterbooleantrue
Whether the motion should be applied when the element is mounted.
unmountOnLeavebooleantrue
Whether the element should be unmounted when the motion is not applied.
namestring—
The name of the motion. It can be a predefined motion name or a custom one. phases: [name]-enter [name]-enter-active [name]-enter-to [name]-leave [name]-leave-active [name]-leave-to
typeMotionType—
The type of the motion, valid values 'transition' and 'animation'.
disabledbooleanfalse
Whether the motion is disabled.
appearbooleanfalse
Whether the motion should appear.
enterbooleantrue
Whether the motion should enter.
leavebooleantrue
Whether the motion should leave.
durationMotionDuration—
The duration of the motion.
hideStrategy"none" | "display" | "visibility"—
The hide strategy of the motion. - `'display'` - hides with `display: none` - `'visibility'` - hides with `visibility: hidden` - `'none'` - no hiding, CSS handles it (e.g. height-based)
cssVarPrefixstring—
CSS variable prefix for motion-related variables (e.g. `'p'` produces `--p-height` ).
enterFromClassNamestring—
The enter from class of the motion.
enterToClassNamestring—
The enter to class of the motion.
enterActiveClassNamestring—
The enter active class of the motion.
leaveFromClassNamestring—
The leave from class of the motion.
leaveToClassNamestring—
The leave to class of the motion.
leaveActiveClassNamestring—
The leave active class of the motion.
onBeforeEnter(event?: MotionEvent) => void—
Callback fired before the enter transition/animation starts.
onEnter(event?: MotionEvent) => void—
Callback fired when the enter transition/animation starts.
onAfterEnter(event?: MotionEvent) => void—
Callback fired after the enter transition/animation ends.
onEnterCancelled(event?: MotionEvent) => void—
Callback fired when the enter transition/animation is cancelled.
onBeforeLeave(event?: MotionEvent) => void—
Callback fired before the leave transition/animation starts.
onLeave(event?: MotionEvent) => void—
Callback fired when the leave transition/animation starts.
onAfterLeave(event?: MotionEvent) => void—
Callback fired after the leave transition/animation ends.
onLeaveCancelled(event?: MotionEvent) => void—
Callback fired when the leave transition/animation is cancelled.

Accessibility#

No keyboard behavior — a primitive for animation that does not affect accessibility. See Primitive for full WAI-ARIA compliance details.